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线段树也是一种用空间换取时间和代码量的做法.

posted @ 2017-10-07 23:25  Dilthey  阅读(262)  评论(0编辑  收藏  举报