这是我写的第一个线段树题,这种题过程很抽象,代码不容易理解,整整写了三小时,修BUG修了很久,不过还好过了。
思路:这个有点像二分的思想,根节点就是全部兵营,下来的第一个左子结点是全部兵的左半,右子节点是剩下的一半,经过重重递归二分,递归的边界就是只剩一个元素,即左子节点等于右子节点,这样,线段树就构造完成了,增删查改都是通过遍历来找到特定区间或元素,再改变它的值。
下面附上AC代码:
#include<cstdio>
#include<string.h>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
const int N=5e4+10;
int str[N];
int m,n;
int s;struct tree
{int sum,l,r;
}node[N*4];void build_tree(int ans,int ll,int rr)//ans是根节点!!!
{if( ll == rr ){node[ans].l = node[ans].r = ll;node[ans].sum = str [ll];return ;}node[ans].l = ll;node[ans].r = rr;//printf("Z");int mid = (ll + rr )>>1;//printf("C");build_tree(ans<<1,ll,mid);build_tree(ans<<1|1,mid+1,rr);node[ans].sum = node [ans<<1].sum + node[ans<<1|1].sum ;
}void update(int ans,int pos,int value)//更新数值
{if(node[ans].l == pos && node[ans].r == pos){node[ans].sum += value ;return ;}int mid = (node[ans].l+node[ans].r)>>1;if(pos <= mid){update(ans<<1,pos,value);}else{update(ans<<1|1,pos,value);}node[ans].sum = node[ans<<1].sum + node[ans<<1|1].sum ;
}void query(int ans,int ll,int rr)
{int mid = (node[ans].l+node[ans].r)>>1;if(node[ans].l == ll && node[ans].r == rr){s += node[ans].sum;return ;}else if( ll > mid ){query(ans<<1|1,ll,rr);}else if( rr <= mid ){query(ans<<1,ll,rr);}else{query(ans<<1,ll,mid);query(ans<<1|1,mid+1,rr);}
}int main()
{int t,x,y;int cas=0;char ch[10];scanf("%d",&t);while(t--){scanf("%d",&m);for(int i=1;i<=m;i++)scanf("%d",&str[i]);printf("Case %d:\n",++cas);build_tree(1,1,m);while(~scanf("%s",ch),ch[0]!='E'){scanf("%d%d",&x,&y);if(ch[0] == 'A'){update(1,x,y);//printf("A");}else if(ch[0] == 'S'){// printf("S");update(1,x,-y);}else if(ch[0] == 'Q'){s=0;//printf("Q");query(1,x,y);printf("%d\n",s);}}}return 0;
}