by zyq / 2014 / 7
树状数组何其牛逼只能这么形容啊。
首先,网上好多对树状数组基础知识讲解的在这就不细讲了。可以参考
http://blog.csdn.net/shahdza/article/details/6314818 (内容比较老了)
下面总结一下树状数组的题型 :
1.最简单的单点更新区间查询 。 其实这个是树状数组的精髓了,不过入门的时候都会做些简单题找感觉吧。
下面附上简单题找感觉,动脑子的题后面贴。
http://poj.org/problem?id=2299
http://poj.org/problem?id=2352
http://poj.org/problem?id=1195 (二维的裸题呢)
http://poj.org/problem?id=2481
http://poj.org/problem?id=2029 (又是一个二维的裸题)
2.插线问点问题:
这是一个经典问题,题目描述为:给连续区间内同时给出某种操作。 然后询问单点的值是多少。
例如:把区间【a,b-1】内的数同时加上v,然后询问c点的值。 我们可以这么操作: 在更新a处的值(加上v) ,然后更新b 处的值(减去v)
这样任何落在区间【a,b-1】的点都会加上1不在区间上的点都不变。
可以参考上图
下面附上一道练习:
http://poj.org/problem?id=2155
http://acm.hdu.edu.cn/showproblem.php?pid=3584 (三维问题)
http://acm.hdu.edu.cn/showproblem.php?pid=4267 (维护多颗树状数组问题)
http://acm.hdu.edu.cn/showproblem.php?pid=5057 (维护多颗树状数组问题)
插线问点是离线树状数组的基础问题哦。。
3:区间修改区间查询的问题 。
这个问题显得不是那么重要(用线段树组搞很简单的)。用树状数组搞就是在深入理解下他的用法。
我们可以维护两个树状数组。
具体可以搞出 http://poj.org/problem?id=3468
我的代码:
by cao ni ma
hehe
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <list>
#include <queue>
#include <stack>
using namespace std;
typedef long long LL;
const int MAX = 100000+10;
const int inf = 0x3f3f3f3f;
LL C[2][MAX];
int n,m;
int lowbit(int x) {return x&-x;}
void add(LL *C,int x,LL val) {
for(int i=x;i<=n;i+=lowbit(i)) C[i]+=val;
}
LL sum(LL *C,int x) {
LL res=0;
for(int i=x;i;i-=lowbit(i)) res+=C[i];
return res;
}
LL val[MAX]; char str[3];
int main()
{
//freopen("in","r",stdin);
//freopen("out","w",stdout);
LL a,b,c;
while(scanf("%d %d",&n,&m)==2) {
memset(C,0,sizeof(C));
for(int i=1;i<=n;i++) {
scanf("%I64d",&val[i]);
add(C[0],i,val[i]);
}
for(int i=0;i<m;i++) {
scanf("%s",str);
if(str[0]=='Q') {
scanf("%I64d %I64d",&a,&b);
LL res=sum(C[1],b)*b-sum(C[1],a-1)*(a-1)+sum(C[0],b)-sum(C[0],a-1);
printf("%I64d\n",res);
}
else {
scanf("%I64d %I64d %I64d",&a,&b,&c);
add(C[1],a,c);
add(C[1],b+1,-c);
add(C[0],a,-c*(a-1));
add(C[0],b+1,b*c);
}
}
}
return 0;
}