题目链接: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;
}
(如有错误,欢迎指正,转载请注明出处)