题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=123
题目分析:这里应用的是区间树,不过在插入数据的时候,遇到第一个完全包含与要插入的区间时,将数据加到里面。因为这道题,其实抽象了以后就是,每一次加数据,相当于是在相应的区间上面加,询问的时候,将x通过的每一个区间的数据相加即可。关于区间树的更多介绍,有时间了会来完善的~今天去跳舞咯~
OK,现在来补充一下这道题的思路,引用百度百科上面的一个图来解释说明:
上图明显是一个树的形式撒,把树从上到下从左到右一次标记为1,2,.....然后就能明白程序中的编号了。然后关于树的操作,大家懂的~各种递归就可以了~
不过这里有一个优化处理,因为这里的应用是区间更新,单点取值,所以在插入数值的时候,不用访问到最底下的节点,遇到一个包含于插入区间的区间,就返回。这里需要自己好好体会一下~
#include<stdio.h>
const int N = 1000002;
struct TREE
{
int Left;
int Right;
int num;
};
TREE tree[N<<2];
void Build(int root, int l, int r)
{
tree[root].Left = l;
tree[root].Right = r;
tree[root].num = 0;
if(l < r)
{
int m = (l + r)>>1;
Build(root<<1, l, m);
Build(root<<1|1, m + 1, r);
}
}
void Insert(int root, int b, int e, int v)
{
//[b,e]覆盖了root表示的区间
if(b <= tree[root].Left && tree[root].Right <= e)
{
tree[root].num += v;
return;
}
int m = (tree[root].Left + tree[root].Right)>>1;
//[b,e]位于root的左半区间
if(e <= m)
Insert(root<<1, b, e, v);
else if(b > m)//[b,e]位于root的右半区间
Insert(root<<1|1, b, e, v);
else//[b,e]与两个区间都相交
{
Insert(root<<1, b, m, v);
Insert(root<<1|1, m + 1, e, v);
}
}
int Query(int root, int x)
{
if(tree[root].Left == tree[root].Right)
return tree[root].num;
int m = (tree[root].Left + tree[root].Right)>>1;
int sum = tree[root].num;
if(x <= m)//询问x所在的那部分区间
sum += Query(root<<1, x);
else
sum += Query(root<<1|1, x);
return sum;
}
int main()
{
int n,m;
int b,e,v;
char str[10];
int i;
while(scanf("%d %d", &n, &m) != EOF)
{
Build(1, 1, m);
for(i = 0; i < n; ++i)//这里最开始写成m了,被坑了
{
scanf("%s", str);
if(str[0] == 'A')
{
scanf("%d %d %d", &b, &e, &v);
Insert(1, b, e, v);
}
else
{
scanf("%d", &b);
printf("%d\n", Query(1, b));
}
}
}
return 0;
}