///
作者:tt2767
声明:本文遵循以下协议自由转载-非商用-非衍生-保持署名|Creative Commons BY-NC-ND 3.0
查看本文更新与讨论请点击:http://blog.csdn.net/tt2767
链接被删请百度: CSDN tt2767
///
简单线段树求动态区间和
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166
#include<string>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define lch(x) ((x) << 1)
#define rch(x) ((x)<<1|1)
#define dad(x) ((x)>>1)
typedef long long int LL;
const int N = 10 + 1000000;
int sum[N];
void build(int l,int r,int rt);
void updata(int mark,int val ,int l,int r,int rt);
int query(int x,int y ,int l ,int r ,int rt) ;
void pushup(int rt);
int main()
{
int Case, tot = 1;
scanf("%d", &Case);
while(Case--)
{
printf("Case %d:\n", tot++);
int n;
scanf("%d", &n);
build(1,n,1);
char q[10];
while (scanf("%s", q) ==1&& q[0] != 'E')
{
int x, y;
scanf("%d%d", &x, &y);
if (q[0] == 'Q')
printf("%d\n", query(x, y, 1, n, 1));
else if (q[0] == 'S')
updata(x, -y, 1, n, 1);
else
updata(x, y, 1, n, 1);
}
}
return 0;
}
void pushup(int rt)
{
sum[rt] = sum[lch(rt)] + sum[rch(rt)]; //父节点的值为左右儿子之和
//虽然只更新了一边,但下边代码保证每个值都更新过
}
void build(int l,int r,int rt)
{
if (l == r)
{
scanf("%d",&sum[rt]); //当区间小到一个点的时候为它赋值
return;
}
int mid = (r+l) >>1;
build(l,mid,lch(rt) ); //递归建树
build(mid +1,r,rch(rt));
pushup(rt); //每次从底向上为父节点求值
}
void updata(int mark,int val ,int l,int r,int rt)
{
if(l == r)
{
sum[rt] += val;//范围精确到一个点的时候更新它
}
else
{
int mid = (l+r)>>1;
if(mark <= mid) updata(mark,val,l,mid,lch(rt));
else updata(mark,val,mid+1,r,rch(rt));
pushup(rt); //更新父节点的值
}
}
int query(int x,int y ,int l ,int r ,int rt)
{
if(x <= l && r <= y)
return sum[rt]; //已经找到被查询的范围返回
int ans = 0;
int mid = (l+r)>>1;
if(x <= mid) ans += query(x,y,l,mid, lch(rt));
if( mid < y) ans+= query(x,y,mid+1,r ,rch(rt));
return ans; //所有分区间的组合就是最终结果
}