线段树的基本操作,具体看代码注释。
View Code
#include <iostream>
#include <string>
using namespace std;
const int MAX = 50005;
struct Tree
{
int left; int right; int num;
}tr[MAX*3];
int arr[MAX],n,t,a,b,ans;
string cmd;
void build(int l,int r,int now) // 构造线段树
{
tr[now].left = l; tr[now].right = r;
if(l == r) {tr[now].num = arr[l]; return;} //编号为now的叶子节点保存第now个兵营的士兵数
int mid = (l + r)>>1;
build(l,mid,now<<1); // 递归构造左子树
build(mid+1,r,(now<<1)+1); // 递归构造右子树
tr[now].num = tr[now<<1].num + tr[(now<<1)+1].num; // 父亲节点保存左右子树的士兵之和
}
void modify(int l,int r,int now)
{
if(tr[now].left == tr[now].right) {tr[now].num += b; return;} // 找到要修改的兵营叶子节点
int mid = (tr[now].left + tr[now].right)>>1;
if(a <= mid) // 要插入的兵营在左子树
{
modify(l,r,now<<1);
}
else if(a > mid) // 要插入的的兵营在右子树
{
modify(l,r,(now<<1)+1);
}
tr[now].num = tr[now<<1].num + tr[(now<<1)+1].num; // 父亲节点保存左右子树的士兵之和
}
void query(int sta,int end,int now) //查询[sta,end]之间的士兵数
{
if(sta == tr[now].left && end == tr[now].right) {ans += tr[now].num; return;}
int mid = (tr[now].left + tr[now].right) >> 1;
if(end <= mid)
{
query(sta,end,now<<1);
}
else if(sta > mid)
{
query(sta,end,(now<<1)+1);
}
else
{
query(sta,mid,now<<1);
query(mid+1,end,(now<<1)+1);
}
}
int main()
{
int i;
scanf("%d",&t);
for(int c = 1;c <= t;++c)
{
scanf("%d",&n);
for(i = 1;i <= n;++i) scanf("%d",&arr[i]);
build(1,n,1);
printf("Case %d:\n",c);
while(true)
{
cin>>cmd;
if(cmd[0] == 'E') break;
scanf("%d %d",&a,&b);
if(cmd[0] == 'A')
{
modify(1,n,1);
}
else if(cmd[0] == 'S')
{
b = -b;
modify(1,n,1);
}
else
{
ans = 0;
query(a,b,1);
printf("%d\n",ans);
}
}
}
return 0;
}