#include
#define N 50005
struct T
{
int l,r;
int sum;
}t[3*N];//一般开3n
int a[N];
void build(int root,int l,int r)//此函数递归构造线段树
{
t[root].l=l;t[root].r=r;
//printf("%d %d %d\n",root,l,r);
if(l==r)如果左==右说明此节点只有一个数了
{
t[root].sum=a[l];
return;
}
int m=(l+r)/2;
build(root*2,l,m);//习惯上构造[l,m],[m+1,r]这样的闭区间
build(root*2+1,m+1,r);
t[root].sum=t[root*2].sum+t[root*2+1].sum;//节点记录这段的和
}
void Update(int root,int x,int num)//递归更新数据
{
int l=t[root].l;
int r=t[root].r;
int mid=(l+r)/2;
if(x==l&&x==r)//递归到了那个数字的节点
{
t[root].sum+=num;
return;
}
if(x>mid)//进入右子树
Update(2*root+1,x,num);
else Update(2*root,x,num);//进入左子树
t[root].sum+=num;
}
int query(int root,int l,int r)//递归求和
{
int m=(t[root].l+t[root].r)/2;
if(t[root].l==l && t[root].r==r)//同样
return t[root].sum;
if(t[root].l==t[root].r)return 0;
if(r<=m)//如果区间在mid左边,进入左子树
return query(root*2,l,r);
else if(l>m)//在右边进入右子树
return query(root*2+1,l,r);
else//跨越了两个节点就加两边子树相应小区间的和
return query(root*2,l,m)+query(root*2+1,m+1,r);
}
int main()
{
int t,n,x,y;
char q[20];
scanf("%d",&t);
int tt=1;
while(t--)
{
printf("Case %d:\n",tt);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
build(1,1,n);//从节点1开始建
while(scanf("%s",q))
{
if(q[0]=='E')break;
else scanf("%d%d",&x,&y);
if(q[0]=='Q')
{
printf("%d\n",query(1,x,y));
}
else if(q[0]=='A')
{
Update(1,x,y);
}
else if(q[0]=='S')
{
y=-y;
Update(1,x,y);
}
}
tt++;
}
}
Accepted。也可以用树状数组做,效率可能高一点。