HDU 1166 - 敌兵布阵 - [单点修改、区间查询zkw线段树]
题还是那个题:http://www.cnblogs.com/dilthey/p/6827959.html
不过我们今天换一种线段树实现来做这道题;
关于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线段树也是一种用空间换取时间和代码量的做法.
转载请注明出处:https://dilthey.cnblogs.com/