题目链接:NYOJ 116 士兵杀敌(二)
这一个是线段树的入门级水题,本题要求我们给出某个区间的区间和。这个问题和线段树的单点更新还是基本一致的。只要把单点更新中的值覆盖变为值得叠加,这一题便可以轻松解决了。如果不知道线段树的单点更新,请移步:传送门
【代码如下】
#include <stdio.h> #include <string.h> #define MAXN 1<<21 //lg100000 约等于 21 typedef struct{ int left,right; int sum_kill; //杀人数 }Soldier; Soldier node[MAXN]; int father[MAXN>>1]; void build(int i,int left,int right){ node[i].left = left; node[i].right = right; node[i].sum_kill = 0; if(left == right){ father[left] = i; return ; } build(i<<1,left,(left+right)/2); build(2*i+1,1+(left+right)/2,right); return ; } void Updata(int ri){ if(ri == 1) return ; int fa = ri/2; //只要将单点问题的这里变成,下边这样就可以了,不明白的可以想想为什么 node[fa].sum_kill = node[2*fa].sum_kill + node[2*fa+1].sum_kill; Updata(fa); } int SK; void Query(int i,int left,int right){ if(node[i].left == left && node[i].right == right){ //这里也是一个和单点问题有区别的 地方 ,把原先单点更新问题中的值覆盖,变为了叠加 SK += node[i].sum_kill; return ; } if(left <= node[2*i].right){ if( right <= node[2*i].right ) Query(2*i,left,right); else Query(2*i,left,node[2*i].right); } if(right >= node[2*i+1].left){ if(left >= node[2*i+1].left) Query(2*i+1,left,right); else Query(2*i+1,node[2*i+1].left,right); } return ; } int main(){ char op[10]; int a,b,i; int N,M,tmp_kill; scanf("%d%d",&N,&M); build(1,1,N); for(i = 1; i <= N; i++){ scanf("%d",&tmp_kill); node[father[i]].sum_kill += tmp_kill; Updata(father[i]); } while(M--){ getchar(); scanf("%s",op); SK = 0; if(!strcmp(op,"QUERY")){ scanf("%d%d",&a,&b); Query(1,a,b); printf("%d\n",SK); }else if(!strcmp(op,"ADD")){ scanf("%d%d",&a,&b); node[father[a]].sum_kill += b; Updata(father[a]); } } return 0; }(如有错误,欢迎指正,转载请注明出处)