​

不过我们今天换一种线段树实现来做这道题;

关于zkw线段树的讲解:​​https://zhuanlan.zhihu.com/p/29876526​​(而且我还在文章里被@了,超开心的ヾ(≧∇≦*)ヾ)

可以说是讲解非常的清楚了!

 

AC代码(包含了拥有节点更新、区间查询功能的zkw线段树模板):



1 #include<cstdio>
2 #include<cstring>
3 #define MAX 131072
4 int n,m;
5 int tree[MAX];
6 void pushup(int rt){tree[rt]=tree[rt<<1]+tree[rt<<1|1];}
7 void build()
8 {
9 for(m=1;m<n;m<<=1);
10 for(int i=m;i<=2*m-1;i++) tree[i]=0;//初始化叶子结点
11 for(int i=m+1;i<=m+n;i++) scanf("%d",&tree[i]);//存储单点值到叶子结点
12 for(int i=m-1;i;i--) pushup(i);
13 }
14 void update(int pos,int val)
15 {
16 pos+=m;
17 tree[pos]+=val;//更新叶子结点
18 for(pos>>=1;pos;pos>>=1) pushup(pos);
19 }
20 int query(int l,int r)
21 {
22 int ret=0;
23 for(l=l+m-1,r=r+m+1;l^r^1;l>>=1,r>>=1)
24 {
25 if(~l&1) ret+=tree[l^1];
26 if(r&1) ret+=tree[r^1];
27 }
28 return ret;
29 }
30 int main()
31 {
32 int t;
33 scanf("%d",&t);
34 for(int kase=1;kase<=t;kase++)
35 {
36 scanf("%d",&n);
37 build();
38 printf("Case %d:\n",kase);
39 char input[7];
40 while(1)
41 {
42 scanf("%s",input);
43 if(input[0]=='E') break;
44 if(input[0]=='Q')
45 {
46 int l,r;
47 scanf("%d%d",&l,&r);
48 printf("%d\n",query(l,r));
49 }
50 if(input[0]=='A')
51 {
52 int pos,x;
53 scanf("%d%d",&pos,&x);
54 update(pos,x);
55 }
56 if(input[0]=='S')
57 {
58 int pos,x;
59 scanf("%d%d",&pos,&x);
60 update(pos,-x);
61 }
62 }
63 }
64 }


PS. MAX=131072这个也是比较有讲究的,因为n最大是50000,所以对应的我们的m算出来是65536,所以这棵完全二叉树最后一个叶子节点的编号为2 * 65536 - 1 = 131072 - 1.

PS2.其实不难发现,zkw线段树也是一种用空间换取时间和代码量的做法.