链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1166
自己第一次在没有看题解AC出来的线段树,写的可能不是太好,再贴个学长的代码,学习一下
发现自己的Update部分写了很多废话,直接用a[r]里的值就好了,我还传了那么多的值,真傻!
代码:
1 #include<stdio.h> 2 #include<algorithm> 3 #include<stdlib.h> 4 #include<string.h> 5 using namespace std; 6 7 #define Lson r<<1 8 #define Rson r<<1|1 9 10 const int N = 1e6+5; 11 12 struct SegmentTree 13 { 14 int L, R; 15 int sum, e; 16 int Mid() 17 { 18 return (R+L)>>1; 19 } 20 }a[N<<2]; 21 22 void BuildSegTree(int r, int L, int R) 23 { 24 a[r].L=L, a[r].R=R; 25 a[r].e=0; 26 27 if(L==R) 28 { 29 scanf("%d", &a[r].sum); 30 return ; 31 } 32 33 BuildSegTree(Lson, L, a[r].Mid()); 34 BuildSegTree(Rson, a[r].Mid()+1, R); 35 36 a[r].sum = a[Lson].sum + a[Rson].sum; 37 } 38 39 void Update(int r, int L, int R, int i, int e) 40 { 41 a[r].sum += e; 42 43 if(L==R && L==i) 44 return ; 45 46 if(i<=a[r].Mid()) 47 Update(Lson, L, a[r].Mid(), i, e); 48 else if(i>a[r].Mid()) 49 Update(Rson, a[r].Mid()+1, R, i, e); 50 } 51 52 int Query(int r, int L, int R) 53 { 54 if(a[r].L==L && a[r].R==R) 55 return a[r].sum; 56 57 if(R<=a[r].Mid()) 58 return Query(Lson, L, R); 59 else if(L>a[r].Mid()) 60 return Query(Rson, L, R); 61 else 62 { 63 long long Lsum = Query(Lson, L, a[r].Mid()); 64 long long Rsum = Query(Rson, a[r].Mid()+1, R); 65 66 return Lsum + Rsum; 67 } 68 } 69 70 int main() 71 { 72 int t, k=1; 73 scanf("%d", &t); 74 while(t--) 75 { 76 int n; 77 scanf("%d", &n); 78 BuildSegTree(1, 1, n); 79 80 char s[20]; 81 int L, R, i, e; 82 83 printf("Case %d: ", k++); 84 85 while(scanf("%s", s), strcmp(s, "End")) 86 { 87 if(strcmp(s, "Query")==0) 88 { 89 scanf("%d%d", &L, &R); 90 printf("%d ", Query(1, L, R)); 91 } 92 else if(strcmp(s, "Add")==0) 93 { 94 scanf("%d%d", &i, &e); 95 Update(1, 1, n, i, e); 96 } 97 else 98 { 99 scanf("%d%d", &i, &e); 100 Update(1, 1, n, i, -e); 101 } 102 } 103 } 104 return 0; 105 }
学长的代码:
1 #include<stdio.h> 2 #include<math.h> 3 #include<string.h> 4 5 #define maxn 50005 6 7 struct node 8 { 9 int L, R, sum;//左右子树,sum记录区间和 10 int Mid(){return (L+R)/2;} 11 }tree[maxn*4];//为了保险起见一般定义是四倍 12 int val[maxn];//保存每个阵地原来的人数 13 14 void Build(int root, int L, int R)//建树 15 { 16 tree[root].L = L, tree[root].R = R; 17 18 if(L == R) 19 { 20 tree[root].sum = val[L]; 21 return ; 22 } 23 24 Build(root<<1, L, tree[root].Mid());//<<1 运算符相当于乘上 2,因为是数往左移一位 25 Build(root<<1|1, tree[root].Mid()+1, R);//|1, 因为左移后最后一位是0, 所以与1进行|相当于+1 26 27 tree[root].sum = tree[root<<1].sum+tree[root<<1|1].sum;//区间和等于左右区间的和 28 } 29 //k表示需要更新的点,e表示需要更新的值 30 void Insert(int root, int k, int e) 31 { 32 tree[root].sum += e; 33 if(tree[root].L == tree[root].R) 34 return ; 35 36 if(k <= tree[root].Mid()) 37 Insert(root<<1, k, e); 38 else 39 Insert(root<<1|1, k, e); 40 } 41 //查询区间LR的和 42 int Query(int root, int L, int R) 43 { 44 if(tree[root].L == L && tree[root].R == R) 45 return tree[root].sum; 46 47 //如果在左子树区间 48 if(R <= tree[root].Mid()) 49 return Query(root<<1, L, R); 50 else if(L > tree[root].Mid())//如果在右子树区间 51 return Query(root<<1|1, L, R); 52 else 53 {//在左右子树 54 int Lsum = Query(root<<1, L, tree[root].Mid()); 55 int Rsum = Query(root<<1|1, tree[root].Mid()+1, R); 56 57 return Lsum + Rsum; 58 } 59 } 60 61 int main() 62 { 63 int T, t=1; 64 65 scanf("%d", &T); 66 67 while(T--) 68 { 69 int i, N, x, y; 70 71 scanf("%d", &N); 72 73 for(i=1; i<=N; i++) 74 scanf("%d", &val[i]); 75 Build(1, 1, N); 76 77 char s[10]; 78 79 printf("Case %d: ", t++); 80 81 while(scanf("%s", s), s[0] != 'E') 82 { 83 scanf("%d%d", &x, &y); 84 85 if(s[0] == 'A') 86 Insert(1, x, y); 87 else if(s[0] == 'S') 88 Insert(1, x, -y); 89 else 90 { 91 int ans = Query(1, x, y); 92 printf("%d ", ans); 93 } 94 } 95 } 96 97 return 0; 98 }