【Problem】http://acm.hdu.edu.cn/showproblem.php?pid=1166
给定一个数组a[]和一系列的操作,应答每个询问。
操作:Add i x:a[i]+=x Sub i x:a[i]-=x Query l r:询问Σ(a[l..r])
【Analysis】
对于Sub i x操作,完全可以用Add i -x来代替。
标准的线段树,比较简单类型的。具体的可以去看wiki。
【Code】
// Task: 1166
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
using namespace std;
#define nil NULL
class SegmentTree
{
public:
int x; // 节点值
int l,r; // 区间左右标记
SegmentTree*left,*right; // 左右子树
SegmentTree (int L=0,int R=0)
{
l=L,r=R;
x=0;
left=right=nil;
}
}*root;
SegmentTree*Build(int a[],int L,int R)
{
if (L>R) return nil;
else
{
SegmentTree*ret=new SegmentTree(L,R);
if (L==R)
ret->x=a[L];
else
{
int K=(L+R)>>1;
if ((ret->left=Build(a,L,K))!=nil) ret->x+=ret->left->x;
if ((ret->right=Build(a,K+1,R))!=nil) ret->x+=ret->right->x;
}
// cout << L << " " << R << " " << ret->x << endl;
return ret;
}
}
void Add(int i,int x)
{
SegmentTree*p=root;
while (p!=nil)
{
p->x+=x;
int k=(p->l+p->r)>>1;
if (i<=k) p=p->left;
else p=p->right;
}
}
int Query(int l,int r,SegmentTree*p=root)
{
if (p==nil||l>r) return 0;
else
{
int ret=0;
if (p->l==l&&p->r==r) return p->x; // 完美包含
int k=(p->l+p->r)>>1;
if (r<=k) return Query(l,r,p->left); // 全都在左子树
if (l>k) return Query(l,r,p->right); // 全都在右子树
if (l<=k) ret+=Query(l,k,p->left); // 交叉包含左子树部分
if (r>k) ret+=Query(k+1,r,p->right); // 交叉包含右子树部分
// printf("%d(%d)-%d(%d) %d\n",l,p->l,r,p->r,ret);
return ret;
}
}
const int N = 50000;
int n;
int a[N+1];
char cmd[10];
int main()
{
int T;
scanf("%d",&T);
for (int dex=1;dex<=T;dex++)
{
printf("Case %d:\n",dex);
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",a+i);
root=Build(a,1,n);
scanf("%s",cmd);
while (cmd[0]!='E')
{
int l,r;
scanf("%d%d",&l,&r);
switch(cmd[0])
{
case 'A':Add(l,r);break;
case 'S':Add(l,-r);break;
case 'Q':printf("%d\n",Query(l,r));break;
}
scanf("%s",cmd);
}
}
return 0;
}