//hdu 1166
/*
利用线段树解决
每个节点表示一个区间中的和
其对应的子节点是父节点对应的两个子区间的和
树的叶节点是各个值
树的根节点是序列的总和
父亲的区间是[a,b],那么(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b]
*/
#include <stdio.h>
#include <string.h>
int N;
int num[50005];
int btArray[50005*3+10];
//构造线段树,begin-end 区间范围, node节点的序号
void build(int begin, int end ,int node)
{
//叶子节点
if(begin == end)
{
btArray[node] = num[begin];
return ;
}
//父亲节点,其子节点的node为父亲的两倍和两倍加1
else
{
//左孩子
build(begin, (begin+end)/2, node*2);
//右孩子
build((begin+end)/2+1, end, node*2+1);
}
//为父亲节点填值
btArray[node] = btArray[2*node] + btArray[2*node+1];
}
//动态更新线段树数据,包括所有父节点
void update(int begin, int end, int node, int cn, int value)
{
//找到该叶子节点
if(begin==end)
{
btArray[node] += value;
return;
}
//不是叶子节点
else
{
//在左子树上
if(cn<=(begin+end)/2)
{
update(begin, (begin+end)/2, node*2, cn, value);
}
//在右子树上
else
{
update((begin+end)/2+1, end, node*2+1, cn, value);
}
}
btArray[node] += value;
}
//查找对应的区间的和[from, to]
int find(int begin, int end, int from, int to, int node)
{
int mid = (begin+end)/2;
//也许是个子区间。。?
if(begin==from && end==to)
return btArray[node];
if(from>mid) return find(mid+1, end, from, to, node*2+1);
if(to<mid+1) return find(begin, mid, from, to, node*2);
else return find(begin, mid, from, mid, node*2) + find(mid+1, end, mid+1, to, node*2+1);
}
int main()
{
int n; scanf("%d", &n);
N = n;
char cmd[10];
while(n--)
{
int a,b;
int k; scanf("%d", &k);
for(int i=0; i<k; i++)
{
scanf("%d", num+i);
}
build(0, k-1, 1);
printf("Case %d:\n", N-n);
while(true)
{
scanf("%s", cmd);
if(strcmp(cmd, "End")==0) break;
scanf("%d %d", &a, &b);
if(strcmp(cmd, "Query")==0)
{
int res = 0;
if(a<0) a=0; if(b>k) b=k;
res = find(0, k-1, a-1, b-1, 1);
printf("%d\n", res);
}
if(strcmp(cmd, "Add")==0)
{
update(0,k-1,1,a-1,b);
}
if(strcmp(cmd, "Sub")==0)
{
update(0,k-1,1,a-1,-b);
}
}
}
return 0;
}
/*
1
10
1 2 3 4 5 6 7 8 9 10
Add 3 6
Sub 10 2
Add 6 3
End
*/
hdu 1166 线段树
最新推荐文章于 2019-08-24 20:29:00 发布