http://blog.csdn.net/libin56842/article/details/8530197
基础可以看上面这篇文章
风格:
maxn是题目给的最大区间,而节点数要开4倍,确切的说……
lson和rson辨别表示结点的左孩子和右孩子。
PushUp(int rt)是把当前结点的信息更新到父节点
PushDown(int rt)是把当前结点的信息更新给孩子结点。
rt表示当前子树的根(root),也就是当前所在的结点。
思想:
对于每个非叶节点所标示的结点 [a,b],其做孩子表示的区间是[a,(a+b)/2],其右孩子表示[(a+b)/2,b].
构造:
离散化和线段树:
题目:x轴上有若干个线段,求线段覆盖的总长度。
普通解法:设置坐标范围[min,max],初始化为0,然后每一段分别染色为1,最后统计1的个数,适用于线段数目少,区间范围小。
离散化的解法:离散化就是一一映射的关系,即将一个大坐标和小坐标进行一一映射,适用于线段数目少,区间范围大。
例如:[10000,22000],[30300,55000],[44000,60000],[55000,60000].
第一步:排序 10000 22000 30300 44000 55000 60000
第二部:编号 1 2 3 4 5 6
第三部:用编号来代替原数,即小数代大数 。
[10000,22000]~[1,2]
[30300,55000]~[3,5]
[44000,60000]~[4,6]
[55000,60000]~[5,6]
然后再用小数进行普通解法的步骤,最后代换回去。
线段树的解法:线段树通过建立线段,将原来染色O(n)的复杂度减小到 log(n),适用于线段数目多,区间范围小的情况。
离散化的线段树:适用于线段数目多,区间范围大的情况。
构造:
动态数据结构:
struct node{
node* left;
node* right;
……
}
静态全局数组模拟(完全二叉树):
struct node{
int left;
int right;
……
}Tree[MAXN]
http://www.xuebuyuan.com/1470670.html
线段树主要用四种用法
单点更新:
模板:
单点增减,查询线段和
struct node { int l,r,c; }T[MAXN*4]; void PushUp(int rt) { T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c; } void build(int l,int r,int x) { T[x].l = l; T[x].r = r; T[x].c = 0; if (l == r) return; int mid = (l+r)>>1; build(l,mid,x<<1); build(mid+1,r,(x<<1) + 1); } void update(int val,int l,int x) { if(T[x].l == T[x].r && T[x].l == l) { T[x].c += val; return; } int mid = (T[x].l + T[x].r)>>1; if (l > mid) { update(val,l,(x<<1) + 1); } else { update(val,l,x<<1); } PushUp(x); } int n,m,ans; void query(int l,int r,int x) { if(T[x].l == l && T[x].r == r) { ans += T[x].c; return; } int mid = (T[x].l + T[x].r)>>1; if (l > mid) { query(l,r,(x<<1)+1); } else if(r<=mid) { query(l,r,(x<<1)); } else { query(l,mid,(x<<1)); query(mid+1,r,(x<<1)+1); } }
HDU 1166
#include <iostream> #include <string> #include <cstring> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <stack> #include <queue> #include <cctype> #include <vector> #include <iterator> #include <set> #include <map> #include <sstream> using namespace std; #define mem(a,b) memset(a,b,sizeof(a)) #define pf printf #define sf scanf #define spf sprintf #define pb push_back #define debug printf("! ") #define MAXN 55555 #define MAX(a,b) a>b?a:b #define blank pf(" ") #define LL long long #define ALL(x) x.begin(),x.end() #define INS(x) inserter(x,x.begin()) #define pqueue priority_queue #define INF 0x3f3f3f3f struct node { int l,r,c; }T[MAXN*4]; void PushUp(int rt) { T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c; } void build(int l,int r,int x) { T[x].l = l; T[x].r = r; T[x].c = 0; if (l == r) return; int mid = (l+r)>>1; build(l,mid,x<<1); build(mid+1,r,(x<<1) + 1); } void update(int val,int l,int x) { if(T[x].l == T[x].r && T[x].l == l) { T[x].c += val; return; } int mid = (T[x].l + T[x].r)>>1; if (l > mid) { update(val,l,(x<<1) + 1); } else { update(val,l,x<<1); } PushUp(x); } int n,m,ans; void query(int l,int r,int x) { if(T[x].l == l && T[x].r == r) { ans += T[x].c; return; } int mid = (T[x].l + T[x].r)>>1; if (l > mid) { query(l,r,(x<<1)+1); } else if(r<=mid) { query(l,r,(x<<1)); } else { query(l,mid,(x<<1)); query(mid+1,r,(x<<1)+1); } } int main() { int t,i,kase=1; char d[10]; sf("%d",&t); while(t--) { mem(T,0); pf("Case %d: ",kase++); sf("%d",&n); build(1,n,1); for(i=1;i<=n;i++) { int tmp; sf("%d",&tmp); update(tmp,i,1); } while (sf("%s",d) != EOF) { if (d[0] == 'E') break; int x, y; sf("%d%d", &x, &y); if (d[0] == 'Q') { ans = 0; query(x,y,1); pf("%d ",ans); } if (d[0] == 'S') update(-y,x,1); if (d[0] == 'A') update(y,x,1); } } return 0; }
单点替换,查询线段最高
模板:
struct node { int l,r,c; }T[MAXN*4]; void PushUp(int rt) { T[rt].c = max(T[rt<<1].c,T[(rt<<1)+1].c); } void build(int l,int r,int x) { T[x].l = l; T[x].r = r; T[x].c = 0; if (l == r) return; int mid = (l+r)>>1; build(l,mid,x<<1); build(mid+1,r,(x<<1) + 1); } void update(int val,int l,int x) { if(T[x].l == T[x].r && T[x].l == l) { T[x].c = val; return; } int mid = (T[x].l + T[x].r)>>1; if (l > mid) { update(val,l,(x<<1) + 1); } else { update(val,l,x<<1); } PushUp(x); } int n,m,ans; void query(int l,int r,int x) { if(T[x].l == l && T[x].r == r) { ans = max(ans,T[x].c); return; } int mid = (T[x].l + T[x].r)>>1; if (l > mid) { query(l,r,(x<<1)+1); } else if(r<=mid) { query(l,r,(x<<1)); } else { query(l,mid,(x<<1)); query(mid+1,r,(x<<1)+1); } }
hdu 1754
这边要注意,输入字符不要用%c,会导致一些难以预料的问题
#include <iostream> #include <string> #include <cstring> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <stack> #include <queue> #include <cctype> #include <vector> #include <iterator> #include <set> #include <map> #include <sstream> using namespace std; #define mem(a,b) memset(a,b,sizeof(a)) #define pf printf #define sf scanf #define spf sprintf #define pb push_back #define debug printf("! ") #define MAXN 200005 #define MAX(a,b) a>b?a:b #define blank pf(" ") #define LL long long #define ALL(x) x.begin(),x.end() #define INS(x) inserter(x,x.begin()) #define pqueue priority_queue #define INF 0x3f3f3f3f struct node { int l,r,c; }T[MAXN*4]; void PushUp(int rt) { T[rt].c = max(T[rt<<1].c,T[(rt<<1)+1].c); } void build(int l,int r,int x) { T[x].l = l; T[x].r = r; T[x].c = 0; if (l == r) return; int mid = (l+r)>>1; build(l,mid,x<<1); build(mid+1,r,(x<<1) + 1); } void update(int val,int l,int x) { if(T[x].l == T[x].r && T[x].l == l) { T[x].c = val; return; } int mid = (T[x].l + T[x].r)>>1; if (l > mid) { update(val,l,(x<<1) + 1); } else { update(val,l,x<<1); } PushUp(x); } int n,m,ans; void query(int l,int r,int x) { if(T[x].l == l && T[x].r == r) { ans = max(ans,T[x].c); return; } int mid = (T[x].l + T[x].r)>>1; if (l > mid) { query(l,r,(x<<1)+1); } else if(r<=mid) { query(l,r,(x<<1)); } else { query(l,mid,(x<<1)); query(mid+1,r,(x<<1)+1); } } int main() { int t,i,kase=1; while(sf("%d%d",&n,&m)==2) { build(1,n,1); for(i=1;i<=n;i++) { int tmp; sf("%d",&tmp); update(tmp,i,1); } while (m--) { int x,y; char d[2]; sf("%s %d %d",d,&x, &y); //pf("%s %d %d ",d,x,y); if (d[0] == 'Q') { ans = 0; query(x,y,1); pf("%d ",ans); } if (d[0] == 'U') update(y,x,1); } } return 0; }
成段更新
(通常这对初学者来说是一道坎),需要用到延迟标记(或者说懒惰标记),简单来说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or询问到的时候
http://blog.sina.com.cn/s/blog_a2dce6b30101l8bi.html
区间替换,求总和
数组要开4倍才够
第一种思路,标记
模板:
struct node { int l,r,c,f; }T[MAXN<<2]; void PushUp(int rt) { T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c; //pf("%d %d ",rt,T[rt].c); } void PushDown(int rt,int m) { if(T[rt].f) { T[rt<<1].f = T[(rt<<1) + 1].f = T[rt].f; T[rt<<1].c = T[rt].f * (m-(m>>1)); T[(rt<<1)+1].c = T[rt].f * (m>>1); T[rt].f = 0; } } void build(int l,int r,int x) { T[x].l = l; T[x].r = r; T[x].c = 1; T[x].f = 0; if (l == r) return; int mid = (l+r)>>1; build(l,mid,x<<1); build(mid+1,r,(x<<1) + 1); PushUp(x); } void update(int val,int L,int R,int l,int r,int x) { if(L <= l && r <= R) { T[x].f = val; T[x].c = val*(r-l+1); //pf("%d %d %d ",T[x].c,l,r); return; } PushDown(x,r-l+1); //pf("%d %d %d %d %d %d ",val,L,R,l,r,x); int mid = (l + r)>>1; if (L <= mid) { update(val,L,R,l,mid,x<<1); } if(R > mid) { update(val,L,R,mid+1,r,x<<1|1); } PushUp(x); }
第二种思路,杂色
struct node { int l,r,c; }T[MAXN<<2]; void PushUp(int rt) { T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c; } void PushDown(int rt) { if(T[rt].c != -1)//如果该区间只有一种颜色 { T[rt<<1].c = T[rt<<1|1].c = T[rt].c;//由于后面必定对子树操作,所以更新子树的值等于父亲的值 T[rt].c = -1;//由于该区域颜色与修改不同,而且不是给定区域,所以该区域必定为杂色 } } void build(int l,int r,int x) { T[x].l = l; T[x].r = r; T[x].c = 1; if (l == r) return; int mid = (l+r)>>1; build(l,mid,x<<1); build(mid+1,r,(x<<1) + 1); } void update(int val,int L,int R,int x) { if(T[x].c == val) return;//相同则不用修改了 if(T[x].l == L && T[x].r == R)//找到了区间,直接更新 { T[x].c = val; return; } PushDown(x); //父区间为杂色时对所有子节点进行操作 int mid = (T[x].l + T[x].r)>>1; if(L>mid) update(val,L,R,x<<1|1); else if(R<=mid) update(val,L,R,x<<1); else { update(val,L,mid,x<<1); update(val,mid+1,R,x<<1|1); } }
hdu 1698
http://www.tuicool.com/articles/j6N3eaz
这里链接的其实不对,要求总和,所以每个点不能初始化为1
#include <iostream> #include <string> #include <cstring> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <stack> #include <queue> #include <cctype> #include <vector> #include <iterator> #include <set> #include <map> #include <sstream> using namespace std; #define mem(a,b) memset(a,b,sizeof(a)) #define pf printf #define sf scanf #define spf sprintf #define pb push_back #define debug printf("! ") #define MAXN 100000 + 5 #define MAX(a,b) a>b?a:b #define blank pf(" ") #define LL long long #define ALL(x) x.begin(),x.end() #define INS(x) inserter(x,x.begin()) #define pqueue priority_queue #define INF 0x3f3f3f3f struct node { int l,r,c,f; }T[MAXN<<2]; void PushUp(int rt) { T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c; //pf("%d %d ",rt,T[rt].c); } void PushDown(int rt,int m) { if(T[rt].f) { T[rt<<1].f = T[(rt<<1) + 1].f = T[rt].f; T[rt<<1].c = T[rt].f * (m-(m>>1)); T[(rt<<1)+1].c = T[rt].f * (m>>1); T[rt].f = 0; } } void build(int l,int r,int x) { T[x].l = l; T[x].r = r; T[x].c = 1; T[x].f = 0; if (l == r) return; int mid = (l+r)>>1; build(l,mid,x<<1); build(mid+1,r,(x<<1) + 1); PushUp(x); } void update(int val,int L,int R,int l,int r,int x) { if(L <= l && r <= R) { T[x].f = val; T[x].c = val*(r-l+1); //pf("%d %d %d ",T[x].c,l,r); return; } PushDown(x,r-l+1); //pf("%d %d %d %d %d %d ",val,L,R,l,r,x); int mid = (l + r)>>1; if (L <= mid) { update(val,L,R,l,mid,x<<1); } if(R > mid) { update(val,L,R,mid+1,r,x<<1|1); } PushUp(x); } int n,m,ans; void query(int l,int r,int x) { if(T[x].l == l && T[x].r == r) { ans += T[x].c; return; } int mid = (T[x].l + T[x].r)>>1; if (l > mid) { query(l,r,(x<<1)+1); } else if(r<=mid) { query(l,r,(x<<1)); } else { query(l,mid,(x<<1)); query(mid+1,r,(x<<1)+1); } } int a[MAXN]; int main() { int t,i,kase=1; sf("%d",&t); while(t--) { sf("%d",&n); build(1,n,1); sf("%d",&m); for(i=1;i<=m;i++) { int x,y,z; sf("%d%d%d",&x,&y,&z); update(z,x,y,1,n,1); } pf("Case %d: The total value of the hook is %d. ",kase++,T[1].c); } return 0; }
区间增减,区间求和
模板:
struct node { LL l,r,c,f; }T[MAXN<<2]; void PushUp(int rt) { T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c; //pf("%d %d ",rt,T[rt].c); } void PushDown(int rt,int m) { if(T[rt].f) { T[rt<<1].f += T[rt].f; T[(rt<<1) + 1].f += T[rt].f; T[rt<<1].c += T[rt].f * (m-(m>>1)); T[(rt<<1)+1].c += T[rt].f * (m>>1); T[rt].f = 0; } } void build(int l,int r,int x) { T[x].l = l; T[x].r = r; T[x].f = 0; T[x].c = 0; if(l==r) return; int mid = (l+r)>>1; build(l,mid,x<<1); build(mid+1,r,(x<<1) + 1); } void update(int val,int L,int R,int l,int r,int x) { if(L <= l && r <= R) { T[x].f += val; T[x].c += val*(r-l+1); //pf("%d %d %d ",T[x].c,l,r); return; } PushDown(x,r-l+1); //pf("%d %d %d %d %d %d ",val,L,R,l,r,x); int mid = (l + r)>>1; if (L <= mid) { update(val,L,R,l,mid,x<<1); } if(R > mid) { update(val,L,R,mid+1,r,x<<1|1); } PushUp(x); } LL ans; int n,m; void query(int L,int R,int l,int r,int x) { if(L <= l && r <= R) { ans += T[x].c; return; } PushDown(x,r-l+1); int mid = (l + r)>>1; if(L <= mid) query(L,R,l,mid,x<<1); if(R > mid) query(L,R,mid+1,r,x<<1|1); PushUp(x); }
poj 3468
#include <iostream> #include <string> #include <cstring> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <stack> #include <queue> #include <cctype> #include <vector> #include <iterator> #include <set> #include <map> #include <sstream> using namespace std; #define mem(a,b) memset(a,b,sizeof(a)) #define pf printf #define sf scanf #define spf sprintf #define pb push_back #define debug printf("! ") #define MAXN 111111 + 5 #define MAX(a,b) a>b?a:b #define blank pf(" ") #define LL long long #define ALL(x) x.begin(),x.end() #define INS(x) inserter(x,x.begin()) #define pqueue priority_queue #define INF 0x3f3f3f3f struct node { LL l,r,c,f; }T[MAXN<<2]; void PushUp(int rt) { T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c; //pf("%d %d ",rt,T[rt].c); } void PushDown(int rt,int m) { if(T[rt].f) { T[rt<<1].f += T[rt].f; T[(rt<<1) + 1].f += T[rt].f; T[rt<<1].c += T[rt].f * (m-(m>>1)); T[(rt<<1)+1].c += T[rt].f * (m>>1); T[rt].f = 0; } } void build(int l,int r,int x) { T[x].l = l; T[x].r = r; T[x].f = 0; if(l==r) { scanf("%I64d",&T[x].c); return; } int mid = (l+r)>>1; build(l,mid,x<<1); build(mid+1,r,(x<<1) + 1); PushUp(x); } void update(int val,int L,int R,int l,int r,int x) { if(L <= l && r <= R) { T[x].f += val; T[x].c += val*(r-l+1); //pf("%d %d %d ",T[x].c,l,r); return; } PushDown(x,r-l+1); //pf("%d %d %d %d %d %d ",val,L,R,l,r,x); int mid = (l + r)>>1; if (L <= mid) { update(val,L,R,l,mid,x<<1); } if(R > mid) { update(val,L,R,mid+1,r,x<<1|1); } PushUp(x); } LL ans; int n,m; void query(int L,int R,int l,int r,int x) { if(L <= l && r <= R) { ans += T[x].c; return; } PushDown(x,r-l+1); int mid = (l + r)>>1; if(L <= mid) query(L,R,l,mid,x<<1); if(R > mid) query(L,R,mid+1,r,x<<1|1); } int main() { int t,i,kase=1; while(~sf("%d%d",&n,&m)) { build(1,n,1); /* for(i=1;i<=n;i++) { int tmp; sf("%d",&tmp); update(tmp,i,i,1,n,1); } */ for(i=1;i<=m;i++) { int x,y,z; char s[2]; sf("%s",s); if(s[0]=='Q') { ans = 0; sf("%d%d",&x,&y); query(x,y,1,n,1); pf("%I64d ",ans); } else { sf("%d%d%d",&x,&y,&z); update(z,x,y,1,n,1); } } } return 0; }