链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166
题意:
第一行一个整数T,表示有T组数据。
每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工兵营地里开始时有ai个人(1<=ai<=50)。
接下来每行有一条命令,命令有4种形式:
(1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30)
(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30);
(3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数;
(4)End 表示结束,这条命令在每组数据最后出现;
每组数据最多有40000条命令
思路:
题目有多个营地,要求修改一个营地的人数,查询多个营地的总人数
单点修改,区间查询,可以使用线段树
实现:
叶子节点存储单个营地人数,负责修改,父节点存储多个营地的总人数,负责查询。
结构体数组存储节点,需要开营地数量*3的空间才足够存储数据。
#include
#include
#define N 50005
int value[N];
struct node{
int l,r,sumn;
}tree[50000*3];
int Build(int root,int l,int r){
tree[root].l = l;
//左边界和右边界的值,代表节点包含的营地数量
tree[root].r = r;
if(l == r){
//叶子节点,没有子节点,存储单个营地人数
return tree[root].sumn = value[l];
}
int mid = (l+r) >> 1;
int a,b;
a = Build(root<<1,l,mid);
//往下建立左子树和右子树
b = Build(root<<1|1,mid+1,r);
//得到节点的值,从子节点往上,确定各个营地区间的总人数
return tree[root].sumn = a+b;
}
int query(int root,int l,int r){
int ans = 0;
int tl = tree[root].l, tr = tree[root].r;
if(tl > r || tr < l){
//节点不在查询区间内,返回0
return 0;
}
if(tr <= r && tl >= l){
//节点完全包括在查询区间中,返回营地总人数
ans = tree[root].sumn;
return ans;
}
int a,b;
//节点只有部分包括在查询区间中
//往子节点查询,一直到子节点完全包括在查询区间中为止
a = query(root<<1,l,r);
b = query(root<<1|1,l,r);
ans = a+b;
return ans;
}
int add(int root,int index,int num){
int tl = tree[root].l, tr = tree[root].r;
if(tl > index || tr < index){
//节点的子节点中不包含要修改人数的营地
//不再找子节点,返回原值
return tree[root].sumn;
}
if(tl == tr){
if(tl == index){
//对营地人数进行修改
tree[root].sumn+=num;
}
return tree[root].sumn;
}
int a,b;
a = add(root<<1,index,num);
b = add(root<<1|1,index,num);
//根据被修改的叶子节点(单个营地人数)
//改变父节点的值(多个营地的总人数)
return tree[root].sumn = a+b;
}
int main(){
int t;
scanf("%d",&t);
for(int t1 = 1;t1 <= t ;t1++){
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i++){
scanf("%d",&value[i]);
}
Build(1,1,n);//通过数据建线段树
char com[10];
printf("Case %d:\n",t1);
while(scanf("%s",com)){
if(!strcmp(com,"End")){
break;
}
int i,j;
scanf("%d%d",&i,&j);
getchar();
if(!strcmp(com,"Query")){
printf("%d\n",query(1,i,j));
}else if(!strcmp(com,"Add")){
add(1,i,j);
}else if(!strcmp(com,"Sub")){
add(1,i,-j);
}
}
}
}