此题详解参见:poj 3468 树状数组解法
此篇写下自己之前不是很理解的地方。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define MAXN 100005
__int64 initSum[MAXN];
__int64 t1[MAXN], t2[MAXN];
inline __int64 lowbit(__int64 x) {
return x & -x;
}
inline void update(__int64 a[], int x, __int64 c) {
while (x <= MAXN) {
a[x] += c;
x += lowbit(x);
}
}
inline __int64 getSum(__int64 a[], int x) {
__int64 sum = 0;
while (x) {
sum += a[x];
x -= lowbit(x);
}
return sum;
}
//根据公式Sum[x] = SUM(A[i], i=1...x)+(x+1)*SUM(delta[i],i=1...x)-SUM(i*delta[i],i=1...x)求Sum[x]
__int64 Sum(__int64 t1[], __int64 t2[], int x) {
__int64 res = initSum[x];
res += (x+1) * getSum(t1, x);
res -= getSum(t2, x);
return res;
}
int main()
{
int i, n, q, tmp;
memset(initSum, 0, sizeof (initSum));
memset(t1, 0, sizeof (t1));
memset(t2, 0, sizeof (t2));
scanf ("%d%d", &n, &q);
for (i = 1; i <= n; i++) {
scanf ("%d", &tmp);
initSum[i] = initSum[i-1] + tmp;
}
while (q--) {
__int64 sum_a, sum_b;
char ch;
int a, b, c;
getchar();
scanf ("%c", &ch);
if (ch == 'Q') {
scanf ("%d%d", &a, &b);
sum_a = Sum(t1, t2, a-1);
sum_b = Sum(t1, t2, b);
printf("%I64d\n", sum_b-sum_a);
}
else {
scanf ("%d%d%d", &a, &b, &c);
//Sum[x] = SUM(A[i], i=1...x)+(x+1)*SUM(delta[i],i=1...x)-SUM(i*delta[i],i=1...x)
//在成段更新时,是对delta数组进行更新,于是用两个树状数组t1,t2来维护
//两个前缀和SUM(delta[i],i=1...x),SUM(i*delta[i],i=1...x),
//而SUM(A[i], i=1...x)在更新过程中是不变的,所以可以预处理在数组中
//将区间的成段更新转化成对t1,t2两个树状数组的单点更新,使更新复杂度保持O(log(n))
update(t1, a, c); //更新SUM(delta[i],i=1...x)中的delta[a]
update(t2, a, a*c);//更新SUM(i*delta[i],i=1...x)中的delta[a]
//这两个update后,区间A[a...n]每个数都增加了c。
update(t1, b+1, -c);
update(t2, b+1, -(b+1)*c);
//这两个update后,区间A[b+1...n]每个数都减少了c
//完成对区间A[a...b]的更新
}
}
return 0;
}