线段树

hdu4288(离线+离散化+线段树)

这一生的挚爱 提交于 2019-12-02 05:08:32
题目 维护一个从小到大的数列,可以添加和删除数据,询问每个数列下标%5=3的数据的值的和 题解 一开始,一直以为是没排序的,想了好久才发现是排序好的,稍微简单了点 离散化的操作比较简单,用STL中的lower_bound和unique两个函数可以轻松完成 离线的原因是因为线段树的局限性,无法完成删除或者增加节点的操作,因为线段树的大小从一开始必须就是固定的,所以用离线的方式,我们就能够知道数据的数量,按照所有数据的总数建立线段树,这就完成了增加线段树的“增加”操作的变形,删除操作我们可以用一个cnt来记录节点的子节点数,删除操作就是将底层的叶子节点减为0,然后将cnt-1,这样这个节点实际上还是存在的,但因为数值为0,不影响到我们的后续总和计算,用cnt这个变量来消除他对数列下标的影响 线段树的话,没啥难度,就是一个单点更新的线段树,要注意的是左子树加右子树时,需要对右子树的下标进行还原,因为例如右子树的第一个在总数列中的位置就应该是(1+sizeof(左子树)),这个时候cnt变量就起到至关重要的作用了 代码 # include <cstdio> # include <iostream> # include <cstring> # include <algorithm> # define maxn 100010 # define lson rt<<1 # define rson

Hotel (线段树求解连续区间)

前提是你 提交于 2019-12-02 03:35:08
题目链接: https://vjudge.net/problem/POJ-3667 题目大意:n个连续的房间m个操作。操作分两种, 第一种以1 x形式给出,找到最左的能连续容下x个人的连续房间,并输出左端点的编号,如果找不到就输出0. 第二种以2 l x的形式给出,表示以l为起点的x个房间都清空。 思路: 采用线段树去维护最大连续区间。具体的讲解可以看: https://www.cnblogs.com/lonely-wind-/p/11667471.html 1 #include <math.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <iostream> 5 #include <algorithm> 6 #include <string> 7 #include <string.h> 8 #include <vector> 9 #include <map> 10 #include <stack> 11 #include <set> 12 //#include <random> 13 14 #define ll long long 15 #define ls nod<<1 16 #define rs (nod<<1)+1 17 const int maxn = 1e5 + 10; 18 19 20 struct

Vases and Flowers (二分 + 线段树)

。_饼干妹妹 提交于 2019-12-02 03:32:36
题目链接: https://vjudge.net/contest/332656#problem/H 题意: n个花瓶,m个操作,花瓶里面有的有花,有的是空的。 1 x y 表示从第x个位置开始查y多花,若一朵花也插不上输出"Can not put any one.",反之输出插花的左位置和右位置。 2 操作是清除区间[a,b]的花。并输出清除了多少花。 思路: 线段树维护区间,然后每次二分查找满足要求的第一个位置。 1 #include <math.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <iostream> 5 #include <algorithm> 6 #include <string> 7 #include <string.h> 8 #include <vector> 9 #include <map> 10 #include <stack> 11 #include <set> 12 #include <random> 13 14 #define ll long long 15 const int maxn = 1e5 + 10; 16 17 int n,m; 18 19 struct Node { 20 int l,r; 21 int val; 22 int lazy; 23 }tree[maxn<

线段树求后继+环——cf1237D

廉价感情. 提交于 2019-12-02 03:03:06
/* 首先开三倍消环(两倍是不够的),倒序求值,线段树找一下后继即可 */ #include<bits/stdc++.h> using namespace std; #define N 300005 int n,a[N],ans[N]; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int Max[N<<2],Min[N<<2],pos1,pos2; void build(int l,int r,int rt){ Max[rt]=0;Min[rt]=1e9+7; if(l==r){ Max[rt]=Min[rt]=a[l]; return; } int m=l+r>>1; build(lson);build(rson); Max[rt]=max(Max[rt<<1],Max[rt<<1|1]); Min[rt]=min(Min[rt<<1],Min[rt<<1|1]); } void query1(int L,int R,int v,int l,int r,int rt){//找第一个比v大的后继 if(l==r){ if(Max[rt]>v)pos1=min(pos1,l); return; } int m=l+r>>1; if(L<=l && R>=r){//可以在区间里二分了 if(Max[rt<<1]>v) query1

P3372 【模板】线段树 1

流过昼夜 提交于 2019-12-02 02:55:07
P3372 【模板】线段树 1 1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 1e5+5; 5 ll a[maxn], add[maxn*4], sum[maxn*4]; 6 ll n, m; 7 void pushup(int rt) { 8 sum[rt] = sum[rt*2]+sum[rt*2+1]; 9 } 10 void pushdown(int rt, int l, int r) { 11 int mid = (l+r)/2; 12 sum[rt*2] = sum[rt*2]+add[rt]*(mid-l+1); 13 sum[rt*2+1] = sum[rt*2+1]+add[rt]*(r-mid); 14 add[rt*2] = add[rt*2]+add[rt]; 15 add[rt*2+1] = add[rt*2+1]+add[rt]; 16 17 add[rt] = 0; 18 } 19 void build(int l, int r, int rt) { 20 add[rt] = 0; 21 if (l == r) { 22 sum[rt] = a[l]; 23 return; 24 } 25 int mid = (l

【线段树(sum,add)】P1083 借教室

浪子不回头ぞ 提交于 2019-12-02 02:09:11
1 #include<iostream> 2 #include<string> 3 #include<queue> 4 #include<stack> 5 #include<vector> 6 #include<map> 7 #include<cstdio> 8 #include<cstdlib> 9 #include<algorithm> 10 #include<set> 11 #include<list> 12 #include<iomanip> 13 #include<cstring> 14 #include<cmath> 15 #include<limits> 16 using namespace std; 17 18 #define au auto 19 #define debug(i) cout<<"<debug> "<<i<<"<\debug>"<<endl 20 #define mfor(i,a,b) for(register int i=(a);i<=(b);i++) 21 #define mrep(i,a,b) for(register int i=(a);i>=(b);i--) 22 #define LLL __int128 23 #define Re register 24 #define il inline 25 #define mem(a,b)

线段树模板二

感情迁移 提交于 2019-12-02 01:55:40
题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 输入格式 第一行包含三个整数N、M、P,分别表示该数列数字的个数、操作的总个数和模数。 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k 操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k 操作3: 格式:3 x y 含义:输出区间[x,y]内每个数的和对P取模所得的结果 输出格式 输出包含若干行整数,即为所有操作3的结果。 输入输出样例 输入 #1 复制 5 5 38 1 5 4 2 3 2 1 4 1 3 2 5 1 2 4 2 2 3 5 5 3 1 4 输出 #1 复制 17 2 #include<bits/stdc++.h> typedef long long ll; using namespace std; const int maxn=2e5+9; struct tree{ int l,r; ll sum,add,mul; }a[maxn<<2]; ll s[maxn],p; void update(int k) { a[k].sum=(a[k<<1].sum+a

线段树

元气小坏坏 提交于 2019-12-02 00:44:37
直接上代码... #include<cstdio> using namespace std; int n,p,a,b,m,x,y,ans; struct node { int l,r,w,f; }tree[400001]; inline void build(int k,int ll,int rr)//建树 { tree[k].l=ll,tree[k].r=rr; if(tree[k].l==tree[k].r) { scanf("%d",&tree[k].w); return; } int m=(ll+rr)/2; build(k*2,ll,m); build(k*2+1,m+1,rr); tree[k].w=tree[k*2].w+tree[k*2+1].w; } inline void down(int k)//标记下传 { tree[k*2].f+=tree[k].f; tree[k*2+1].f+=tree[k].f; tree[k*2].w+=tree[k].f*(tree[k*2].r-tree[k*2].l+1); tree[k*2+1].w+=tree[k].f*(tree[k*2+1].r-tree[k*2+1].l+1); tree[k].f=0; } inline void ask_point(int k)//单点查询 { if(tree[k].l=

POJ 1201 Intervals

做~自己de王妃 提交于 2019-12-01 22:42:58
传送门 听说正常写法是差分约束? 我怎么看都是贪心啊,所以就用贪心写了 (其实是我忘记差分约束怎么写了) 考虑把区间按右端点排序,那么对于每个区间,我们考虑选择的数尽量贴着区间右边,因为这样还可以尽量满足之后区间的要求 (显然填在左边对后面没有任何好处,填右边一定比填左边好) 然后这样搞如果直接暴力复杂度是可以卡到 $n^2$ 的,所以考虑用线段树优化一下这个贪心 线段树维护一下当前每个位置是否已经选择,然后对于每个题目限制的区间 $l,r,x$,(区间 $[l,r]$ 内要选择 $x$ 个数) 我们首先把 $x$ 先减去当前 $[l,r]$ 内已经选择的位置数量,然后现在问题就是确定位置 $p$ ,使得把当前 $[p,r]$ 内没有选择的数选择以后恰好满足限制 这个东西显然是可以二分的,然后就做完了,复杂度因为二分时要线段树查询一下所以是 $n \log ^2 max(r) $ 的,已经可以过了 但是我脑子转不过来就是要写线段树上二分 但是正常的线段树上二分是在整颗线段树 $[1,max(r)]$ 上二分,不慌,注意到此时 $(r,max(r)]$ 的所有位置都还没选 所以把原本二分要求的值加上 $max(r)-r$ 即可在整颗线段树上二分了,复杂度 $n \log max(r)$ (如果实在听不懂的话直接看代码或许比较简单?) 线段树维护区间赋值为 $1$

luogu_2605: 基站选址

拈花ヽ惹草 提交于 2019-12-01 21:56:52
洛谷2605:基站选址 题意描述: 有 \(N\) 个村庄在一条直线上,第 \(i(i>1)\) 个村庄的距离第 \(1\) 个村庄的距离为 \(D_i\) 。 需要在这些村庄中建立不超过 \(K\) 个通讯站,在第 \(i\) 个村庄建立基站的费用为 \(C_i\) 。 如果在距离第 \(i\) 个村庄不超过 \(S_i\) 的范围内建立了一个通讯站,那么村庄就被基站覆盖。 如果第 \(i\) 个村庄没有被覆盖,则要向他们补偿,费用为 \(W_i\) 。 现在的问题是,选择基站的位置,使得总花费最小。 数据范围: \(k\leq N,k\leq 100,N\leq2*10^4,D_i\leq 10^9,C_i\leq 10^4,S_i\leq 10^9, w_i\leq 10^4\) 。 输入格式: 第一行包含两个整数 \(N,K\) ,含义如上所述。 第二行包含 \(N-1\) 个整数,分别表示 \(D_2,D_3,...,D_n\) \((\) 与第一个村庄的距离 \()\) ,这 \(N-1\) 个数是递增的。 第三行输入 \(N\) 个整数,表示 \(C_1,C_2,...,C_n\) \((\) 在第 \(i\) 个村庄建基站的费用 \()\) 。 第四行输入 \(N\) 个整数,表示 \(S_1,S_2,...,S_n\) \((\) 第 \(i\) 个基站覆盖的距离