对于树状数组的操作理解的太浅以及学的不够全面
关于一维树状数组的区间修改+区间查询:
引入delta数组 delta[i]表示区间 [i, n] 的共同增量 于是修改区间 [l, r] 时修改 delta[l] 和 delta[r + 1] 即可
查询的时候是查询区间 [l, r] 的和 即sum[r] - sum[l - 1]
sum[i] = a[1]+...+a[i] + delta[1]*i + delta[2]*(i - 1) + delta[3]*(i - 2)+...+delta[i]*1 // a[i]为原始数组
= sigma( a[x] ) + sigma( delta[x] * (i + 1 - x) )
= sigma( a[x] ) + (i + 1) * sigma( delta[x] ) - sigma( delta[x] * x )
于是只需要维护 delta[x] 与 delta[x] * x 的前缀和(即两个树状数组)
写了一个模板
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <map>
#include <set>
#include <queue>
#include <vector>
#define mod 1000000007
#define INF 0x3f3f3f3f
#define fuck() (cout << "----------------------------------------" << endl)
using namespace std;
typedef long long LL;
const int maxn = 100000 + 5;
int n,q;
LL sum[maxn];
LL delta[maxn];
LL delta2[maxn];
LL lowbit(LL x){
return x & (-x);
}
void add(LL x, LL c, LL g[]){
while(x <= n){
g[x] += c;
x += lowbit(x);
}
}
LL query(LL x, LL g[]){
LL ans = 0;
while(x > 0){
ans += g[x];
x -= lowbit(x);
}
return ans;
}
int main(){
while(scanf("%d%d",&n,&q) == 2){
memset(sum, 0, sizeof(sum));
memset(delta, 0, sizeof(delta));
memset(delta2, 0, sizeof(delta2));
for(int i=1; i<=n; i++){
LL c;
scanf("%lld",&c);
sum[i] = sum[i-1] + c;
}
while(q--){
getchar();
char op;
scanf("%c",&op);
if(op == 'Q'){
LL l, r;
scanf("%lld%lld",&l,&r);
LL sum1 = sum[l-1] + l*query(l-1,delta) - query(l-1,delta2);
LL sum2 = sum[r] + (r+1)*query(r,delta) - query(r,delta2);
printf("%lld\n",sum2-sum1);
}
else{
LL l, r ,k;
scanf("%lld%lld%lld",&l,&r,&k);
add(l,k,delta);
add(r+1,-k,delta);
add(l,k*l,delta2);
add(r+1,-k*(r+1),delta2);
}
}
}
return 0;
}
然后是二维树状数组的子矩阵更新+查询
推荐一篇博客http://blog.csdn.net/zearot/article/details/45063297