线段树
1 //线段树的节点 2 //节点包括两部分信息,基本域,和信息域 3 //基本域:左右边界ld,rd. 左右孩子:lc,rc 4 //信息域:key值,如RMQ问题中,信息域中存储的是区间最大值 5 struct Node{ 6 int ld,rd; 7 Node *lc,*rc; 8 int key; 9 }; 10 11 //空树的建立,内含key值的初始化; 12 //一般在主函数中首先调用 Node* root= buildtree(1,n);建立一棵新树 13 Node *buildtree(int a,int b){ 14 Node * p=new Node;//给P申请一块内存 15 p->ld=a; 16 p->rd=b; 17 //{初始化 p->key } 18 if(a==b)return p;//叶子节点 19 p->lc=buildtree(a,(a+b)/2); 20 p->rc=buildtree((a+b)/2+1,b); 21 return p; 22 } 23 24 void insert(Node *T,int a,int b,int key){ 25 if(a<=T->ld&&b>=T->rd){ 26 //{根据key处理T->key; 然后 return ;} 27 } 28 if(a<=(T->ld+T->rd)/2) 29 insert(T->lc,a,b,key); 30 if(b>(T->ld+T->rd)/2) 31 insert(T->rc,a,b,key); 32 //{根据T->lc和T->rc的信息处理T->key} (此处类似于归并排序中最后的合并操作) 33 } 34 35 int search(Node *T,int a,int b){ 36 int res; 37 if(a<=T->ld&&b>=T->rd) 38 // {根据T->key处理res;return res;} 39 if(a<=(T->ld+T->rd)/2) 40 //{根据search(T->lc,a,b)处理res} 41 if(b>(T->ld+T->rd)/2) 42 //根据search(T->rc,a,b)处理res} 43 return res; 44 }
模板:
基础线段树是一些基本操作之间的组合:
基本操作:单点更新、单点查询、区间更新,区间求和、区间最值
1、单点增减,区间求和
http://acm.hdu.edu.cn/showproblem.php?pid=1166
1 View Code 2 3 #include<algorithm> 4 #include<cstring> 5 #include<cstdio> 6 #define MAXN 500000 7 using namespace std; 8 struct SegTree 9 { 10 int left,right; 11 int anssum; 12 }tree[MAXN<<2]; 13 void build(int root,int a,int b) 14 { 15 tree[root].left=a; 16 tree[root].right=b; 17 tree[root].anssum=0; 18 if(a<b) 19 { 20 int M=(a+b)>>1; 21 build(root<<1,a,M); 22 build(root<<1|1,M+1,b); 23 } 24 } 25 void update(int root,int i,int e)//单点增减 26 { 27 int L,M,R; 28 L=tree[root].left; 29 R=tree[root].right; 30 tree[root].anssum+=e; 31 if(L==R) return ; 32 M=(L+R)>>1; 33 if(i<=M) 34 update(root<<1,i,e); 35 else 36 update(root<<1|1,i,e); 37 } 38 int query(int root,int a,int b)//区间求和 39 { 40 int L,M,R; 41 L=tree[root].left; 42 R=tree[root].right; 43 M=(L+R)>>1; 44 if(a==L&&b==R) 45 return tree[root].anssum; 46 if(b<=M) return query(root<<1,a,b); 47 else if(a>M) return query(root<<1|1,a,b); 48 else return query(root<<1,a,M)+query(root<<1|1,M+1,b); 49 } 50 int main() 51 { 52 int test,n,i,a,b,k=1; 53 char s[5]; 54 scanf("%d",&test); 55 while(test--) 56 { 57 scanf("%d",&n); 58 build(1,1,n); 59 for(i=1;i<=n;i++) 60 { 61 scanf("%d",&a); 62 update(1,i,a); 63 } 64 printf("Case %d:\n",k++); 65 while(scanf("%s",s)&&strcmp(s,"End")!=0) 66 { 67 scanf("%d %d",&a,&b); 68 if(s[0]=='Q') printf("%d\n",query(1,a,b)); 69 else if(s[0]=='A') update(1,a,b); 70 else update(1,a,-b); 71 } 72 } 73 return 0; 74 }
2、区间更新、单点访问
http://acm.nyist.net/JudgeOnline/problem.php?pid=123
View Code #include<algorithm> #include<cstring> #include<cstdio> #define MAXN 1000000 using namespace std; struct SegTree { int left,right; int acount; } tree[MAXN<<2]; void build(int root,int a,int b) { tree[root].left=a; tree[root].right=b; tree[root].acount=0; if(a<b) { int M=(a+b)>>1; build(root<<1,a,M); build(root<<1|1,M+1,b); } } void update(int root,int a,int b,int c)//区间更新 { if(a<=tree[root].left&&tree[root].right<=b) { tree[root].acount+=c; return ; } int M=(tree[root].left+tree[root].right)>>1; if(b<=M) update(root<<1,a,b,c); else if(a>M) update(root<<1|1,a,b,c); else { update(root<<1,a,M,c); update(root<<1|1,M+1,b,c); } } int query(int root,int a)//单点访问 { int cnt=tree[root].acount; int M=(tree[root].left+tree[root].right)>>1; if(tree[root].left==tree[root].right) return cnt; if(a<=M) cnt+=query(root<<1,a); else cnt+=query(root<<1|1,a); return cnt; } int main() { int n,m,a,b,c,i; char str[10];//这里被坑了str[5] scanf("%d%d",&m,&n); build(1,1,n); for(i=1; i<=m; i++) { scanf("%s",str); if(str[0]=='A') { scanf("%d%d%d",&a,&b,&c); update(1,a,b,c); } else { scanf("%d",&a); printf("%d\n",query(1,a)); } } return 0; }
3、单点替换、区间最值
http://acm.hdu.edu.cn/showproblem.php?pid=1754
1 View Code 2 3 #include<iostream> 4 #include<cstdio> 5 #define MAXN 200000 6 using namespace std; 7 struct segtree 8 { 9 int left,right; 10 int ansmax; 11 }tree[MAXN<<2]; 12 void build(int root,int a,int b) 13 { 14 tree[root].left=a; 15 tree[root].right=b; 16 tree[root].ansmax=0; 17 if(a<b) 18 { 19 int M=(tree[root].left+tree[root].right)>>1; 20 build(root<<1,a,M); 21 build(root<<1|1,M+1,b); 22 } 23 } 24 void update(int root,int i,int e) 25 { 26 tree[root].ansmax=max(tree[root].ansmax,e); 27 if(tree[root].left==tree[root].right) return ; 28 int M=(tree[root].left+tree[root].right)>>1; 29 if(i<=M) update(root<<1,i,e); 30 else update(root<<1|1,i,e); 31 } 32 int query(int root,int a,int b) 33 { 34 if(tree[root].left==a&&tree[root].right==b) 35 { 36 return tree[root].ansmax; 37 } 38 int M=(tree[root].left+tree[root].right)>>1; 39 if(b<=M) return query(root<<1,a,b); 40 else if(a>M) return query(root<<1|1,a,b); 41 else return max(query(root<<1,a,M),query(root<<1|1,M+1,b)); 42 } 43 int main() 44 { 45 char s; 46 int n,m,a,b,i; 47 while(scanf("%d%d",&n,&m)==2) 48 { 49 build(1,1,n); 50 for(i=1;i<=n;i++) 51 { 52 scanf("%d",&a); 53 update(1,i,a); 54 } 55 for(i=1;i<=m;i++) 56 { 57 scanf("%s%d%d",&s,&a,&b); 58 if(s=='U') update(1,a,b); 59 else printf("%d\n",query(1,a,b)); 60 } 61 } 62 return 0; 63 }
注:单点增减、区间最值(update使用自底向上的方式有点慢)
1 View Code 2 3 #include<iostream> 4 #include<cstdio> 5 #define MAXN 200000 6 using namespace std; 7 struct segtree 8 { 9 int left,right; 10 int ansmax; 11 }tree[MAXN<<2]; 12 void build(int root,int a,int b) 13 { 14 tree[root].left=a; 15 tree[root].right=b; 16 tree[root].ansmax=0; 17 if(a<b) 18 { 19 int M=(tree[root].left+tree[root].right)>>1; 20 build(root<<1,a,M); 21 build(root<<1|1,M+1,b); 22 } 23 } 24 void update(int root,int i,int e) 25 { 26 tree[root].ansmax=max(tree[root].ansmax,e); 27 if(tree[root].left==tree[root].right) return ; 28 int M=(tree[root].left+tree[root].right)>>1; 29 if(i<=M) update(root<<1,i,e); 30 else update(root<<1|1,i,e); 31 } 32 int query(int root,int a,int b) 33 { 34 if(tree[root].left==a&&tree[root].right==b) 35 { 36 return tree[root].ansmax; 37 } 38 int M=(tree[root].left+tree[root].right)>>1; 39 if(b<=M) return query(root<<1,a,b); 40 else if(a>M) return query(root<<1|1,a,b); 41 else return max(query(root<<1,a,M),query(root<<1|1,M+1,b)); 42 } 43 int main() 44 { 45 char s; 46 int n,m,a,b,i; 47 while(scanf("%d%d",&n,&m)==2) 48 { 49 build(1,1,n); 50 for(i=1;i<=n;i++) 51 { 52 scanf("%d",&a); 53 update(1,i,a); 54 } 55 for(i=1;i<=m;i++) 56 { 57 scanf("%s%d%d",&s,&a,&b); 58 if(s=='U') update(1,a,b); 59 else printf("%d\n",query(1,a,b)); 60 } 61 } 62 return 0; 63 }