题目大意:正整数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条命令
解题思路:裸线段树单点更新,区间求和
#include <bits/stdc++.h>
using namespace std;
const int maxn = 50000+100;
int num[maxn];
struct node
{
int l,r;
int value;
}tree[4*maxn];
void build(int id,int l,int r)
{
int mid = (l+r)>>1;
tree[id].l = l;
tree[id].r = r;
if(l == r)
tree[id].value = num[l];
else
{
build(id*2,l,mid);
build(id*2+1,mid+1,r);
tree[id].value = tree[2*id].value+tree[2*id+1].value;
}
}
//将第a个数加上b
void update(int id,int a,int b)
{
tree[id].value += b;
if(tree[id].l == tree[id].r)
return ;
int mid=(tree[id].l+tree[id].r)>>1;
if(a <= mid)
update(id*2,a,b);
else
update(id*2+1,a,b);
}
//求区间a到b的值和
int call(int id,int a,int b)
{
if(tree[id].l == a&&tree[id].r == b)
{
return tree[id].value;
}
int mid = (tree[id].l+tree[id].r)>>1;
if(b <= mid)
return call(2*id,a,b);
else if(a > mid)
return call(2*id+1,a,b);
else
return call(id*2,a,mid) + call(id*2+1,mid+1,b);
}
int main()
{
int t,n;
char str[10];
int a,b;
scanf("%d",&t);
int cas = 1;
while(t--)
{
scanf("%d",&n);
for(int i = 1;i <= n;i++)
scanf("%d",&num[i]);
build(1,1,n);
printf("Case %d:\n",cas++);
while(scanf("%s",str) != EOF)
{
if(!strcmp(str,"End"))
break;
if(str[0] == 'A')
{
scanf("%d%d",&a,&b);
update(1,a,b);
}
else if(str[0] == 'S')
{
scanf("%d%d",&a,&b);
update(1,a,-b);
}
else if(str[0] == 'Q')
{
scanf("%d%d",&a,&b);
int ans = call(1,a,b);
printf("%d\n",ans);
}
}
}
return 0;
}