**[線段樹 點更新 段查詢]A - 敵兵佈陣 HDU - 1166 **
題目大意:有1-n個敵營,每個敵營有一定數目的敵人。三種操作:1,i敵營人數增加j;2,i敵營人數減少j;3,查詢區間i,j敵營人數的總和。
分析:很顯然更新要到點,查詢則是區間,所以結點只需要保存區間人數總和即可。
對於減操作,只需增加-j即可。
#include<stdio.h>
#include<algorithm>
using namespace std;
struct node
{
int l,r;
int sum;
};
node tree[200005];
int mid(int root)
{
return (tree[root].l+tree[root].r)/2;
}
void BuildTree(int root,int l,int r)
{
tree[root].l=l;
tree[root].r=r;
tree[root].sum=0;
if(l!=r)
{
BuildTree(2*root+1,tree[root].l,mid(root));
BuildTree(2*root+2,mid(root)+1,tree[root].r);
}
}
void Insert(int root,int i,int v)
{
if(tree[root].l==tree[root].r)
{
tree[root].sum=v;
return;
}
tree[root].sum+=v;
if(i<=mid(root))
{
Insert(2*root+1,i,v);
}
else
{
Insert(2*root+2,i,v);
}
}
int Query(int root,int a,int b)
{
if(tree[root].l==a&&tree[root].r==b)
{
return tree[root].sum;
}
if(b<=mid(root))
{
return Query(2*root+1,a,b);
}
else if(a>mid(root))
{
return Query(2*root+2,a,b);
}
else
{
return Query(2*root+1,a,mid(root))+Query(2*root+2,mid(root)+1,b);
}
}
void Add(int root,int i,int v)
{
if(tree[root].l==tree[root].r)
{
tree[root].sum+=v;
return;
}
tree[root].sum+=v;
if(i<=mid(root))
{
Add(2*root+1,i,v);
}
else
{
Add(2*root+2,i,v);
}
}
int main()
{
int t;
scanf("%d",&t);
int ans=1;
while(t--)
{
int n;
scanf("%d",&n);
BuildTree(0,1,n);
int t;
for(int i=1;i<=n;i++)
{
scanf("%d",&t);
Insert(0,i,t);
}
char s[10];
printf("Case %d:\n",ans++);
while(scanf("%s",s))
{
if(s[0]=='E')
{
break;
}
else if(s[0]=='Q')
{
int i,j;
scanf("%d %d",&i,&j);
int re=Query(0,i,j);
printf("%d\n",re);
}
else if(s[0]=='A')
{
int i,j;
scanf("%d %d",&i,&j);
Add(0,i,j);
}
else if(s[0]=='S')
{
int i,j;
scanf("%d %d",&i,&j);
Add(0,i,-j);
}
}
}
return 0;
}