一直没写关于线段树的题解,简单的补两个部分。完整的请转https://blog.csdn.net/yrhsilence/article/details/5793699
线段树做了很多,感觉这类题其实比别的算法更简单,只不过代码量比较大。
关于树,大家明白一点就行
父节点 n
—— ——
父节点*2 父节点*2+1
即 n*2 n*2+1
二进制中 左移1位 左移1位+1
下面,我简单说两类,一个是区间求和,一个是区间求最值
1 #include <stdio.h> 2 #include <math.h> 3 #include <stdlib.h> 4 #include <string.h> 5 #include <string> 6 #include <algorithm> 7 #include <iostream> 8 #include <ctype.h> 9 #include <set> 10 #include <map> 11 #include <vector> 12 #include <stack> 13 #include <queue> 14 #define left (now<<1) 15 #define right ((now<<1)+1) 16 #define mid ((l+r)>>1) 17 #define fst first 18 #define snd second 19 using namespace std; 20 typedef long long lint; 21 22 struct segmentTree{ 23 int sum; 24 }; 25 26 int t,n,a[50010]; 27 char str[10]; 28 segmentTree tree[2000010]; 29 30 void buildTree(int now,int l,int r){ //建树 31 if(l == r){ 32 tree[now].sum = a[l]; return; 33 } 34 buildTree(left,l,mid); buildTree(right,mid+1,r); 35 tree[now].sum = tree[left].sum + tree[right].sum; 36 return; 37 } 38 39 void updateTree(int now,int l,int r,int set,int setNum){ //更新树 40 if(l == r){ 41 tree[now].sum += setNum; 42 return; 43 } 44 if(set <= mid){ 45 updateTree(left,l,mid,set,setNum); 46 }else{ 47 updateTree(right,mid+1,r,set,setNum); 48 } 49 tree[now].sum = tree[left].sum + tree[right].sum; 50 } 51 52 int getSum(int now,int l,int r,int ql,int qr){ //求和 53 if(ql == l && qr == r){ 54 return tree[now].sum; 55 } 56 int re = 0; 57 if(ql <= mid){ 58 re += getSum(left,l,mid,ql,min(qr,mid)); 59 } 60 61 if(qr > mid){ 62 re += getSum(right,mid+1,r,max(ql,mid+1),qr); 63 } 64 return re; 65 } 66 67 int main(){ 68 scanf("%d",&t); 69 int ca = 0; 70 while(t--){ 71 ++ca; 72 memset(a,0,sizeof(a)); 73 scanf("%d",&n); 74 for(int i = 1; i <= n; ++i){ 75 scanf("%d",&a[i]); 76 } 77 scanf("%s",str); 78 buildTree(1,1,n); 79 printf("Case %d:n",ca); 80 while(str[0] != 'E'){ 81 if(str[0] == 'A'){ 82 int u,v; 83 scanf("%d%d",&u,&v); 84 updateTree(1,1,n,u,v); 85 }else if(str[0] == 'S'){ 86 int u,v; 87 scanf("%d%d",&u,&v); 88 updateTree(1,1,n,u,-v); 89 }else if(str[0] == 'Q'){ 90 int u,v; 91 scanf("%d%d",&u,&v); 92 int ans = getSum(1,1,n,u,v); 93 printf("%dn",ans); 94 } 95 scanf("%s",str); 96 } 97 } 98 }
(其实有一种后缀数组做这个题更好,这里主要是为了练一下线段树,树状数组可以放一放)
1 #include"stdio.h" 2 #include"string.h" 3 long long lqq[50005]; 4 int n; 5 int lowbit(int x) 6 { 7 return x&(-x); 8 } 9 void insert(int i,int k) 10 { 11 while(i<=n) 12 { 13 lqq[i]+=k; 14 i+=lowbit(i); 15 } 16 } 17 long long getsum(int n) 18 { 19 long long sum=0; 20 while(n) 21 { 22 sum+=lqq[n]; 23 n-=lowbit(n); 24 } 25 return sum; 26 } 27 int main() 28 { 29 int t,i,k,T=1; 30 char s[10]; 31 scanf("%d",&t); 32 while(t--) 33 { 34 printf("Case %d: ",T++); 35 memset(lqq,0,sizeof(lqq)); 36 scanf("%d",&n); 37 for(i=1;i<=n;i++) 38 { 39 scanf("%d",&k); 40 insert(i,k); 41 } 42 scanf("%s",s); 43 while(strcmp(s,"End")) 44 { 45 scanf("%d%d",&i,&k); 46 if(strcmp(s,"Add")==0) 47 insert(i,k); 48 else if(strcmp(s,"Sub")==0) 49 insert(i,-k); 50 else printf("%d ",getsum(k)-getsum(i-1)); 51 scanf("%s",s); 52 } 53 } 54 return 0; 55 }
这个题真的很有意思,而且跟2017年acm区域赛网络资格赛的一个题超级像!!!务必好好看一下
1 #include<iostream> 2 #include<cmath> 3 #include<cstdio> 4 5 //hduoj 1754 G++ 6 7 8 const int MAXN = 800000; 9 using namespace std; 10 11 struct node 12 { 13 int left,right,value; 14 } node[MAXN]; 15 int father[MAXN]; 16 17 int MAX(int x,int y) 18 { 19 return x>=y ? x:y; 20 } 21 22 //建树 23 void Build(int i, int left,int right) 24 { 25 node[i].left = left ; 26 node[i].right = right ; 27 node[i].value = 0; 28 if(left == right) 29 { 30 father[left] = i; 31 return ; 32 } 33 Build((i << 1) , left, (int)( floor(left + right) / 2.0 )); 34 Build((i << 1)+1 , (int)( floor(left + right)/2.0)+1 , right ); 35 } 36 37 38 //更新 39 void Update(int ri) 40 { 41 if( ri == 1) 42 return ; 43 int fi = ri / 2 ; 44 int a,b; 45 a = node[fi<<1].value; 46 b = node[ (fi<<1) +1].value; 47 node[fi].value = MAX(a,b); 48 Update(ri / 2) ; 49 } 50 51 52 //查询 53 int Max; 54 void Query(int i, int l, int r) 55 { 56 if(node[i].left == l && node[i].right == r ) 57 { 58 Max = MAX(Max, node[i].value ); 59 return ; 60 } 61 i = i << 1 ; 62 if( l <= node[i].right ) 63 { 64 if(r <= node[i].right) 65 Query(i, l, r ); 66 else 67 Query(i, l, node[i].right ); 68 } 69 i++; 70 if( r>= node[i].left ) 71 { 72 if( l >= node[i]. left ) 73 Query(i, l, r ); 74 else 75 Query( i, node[i].left, r); 76 } 77 } 78 79 80 //主函数 81 int main() 82 { 83 int n,m,g; 84 while(scanf("%d%d", &n,&m )!=EOF) 85 { 86 Build( 1, 1, n ); 87 for(int i = 1 ; i <= n ; i++ ) 88 { 89 scanf("%d", &g ); 90 node[father[i]].value = g; 91 Update(father[i]); 92 } 93 string op; 94 int a,b; 95 while(m--) 96 { 97 cin>>op>>a>>b; 98 if(op[0] == 'Q') 99 { 100 Max = 0; 101 Query(1,a,b); 102 cout<<Max<<endl; 103 } 104 else 105 { 106 node[father[a]].value = b; 107 Update(father[a]); 108 } 109 } 110 } 111 } 112 /*5 6 113 1 2 3 4 5 114 Q 1 5 115 U 3 6 116 Q 3 4 117 Q 4 5 118 U 2 9 119 Q 1 5 120 121 5 6 5 9*/