用树状数组维护原数组的差分数组,对于区间
[
l
,
r
]
[l,r]
[l,r] 中每一个数加上
v
a
l
val
val,等价于差分数组d[] 中 d[l] += val, d[r+1] -= val,这样区间修改的问题就转化成了例题1中的单点修改,而根据差分的性质,
a
[
i
]
=
∑
j
=
1
i
d
[
j
]
a[i] = \sum_{j=1}^i d[j]
a[i]=∑j=1id[j],故单点查询即转化成了区间求和。
考虑序列
a
a
a 的差分数组
d
d
d,其中
d
[
i
]
=
a
[
i
]
−
a
[
i
−
1
]
d[i] = a[i] - a[i - 1]
d[i]=a[i]−a[i−1]。由于差分数组的前缀和就是原数组,所以
a
i
=
∑
j
=
1
i
d
j
a_i=\sum_{j=1}^i d_j
ai=∑j=1idj。
考虑将区间查询的差分转化。若要查询
a
[
1
]
+
a
[
2
]
+
…
+
a
[
r
]
a[1]+a[2]+ \ldots +a[r]
a[1]+a[2]+…+a[r] ,即
∑
i
=
1
r
a
i
\sum_{i=1}^{r} a_i
∑i=1rai:
进行推导,
∑
i
=
1
r
a
i
=
∑
i
=
1
r
∑
j
=
1
i
d
j
\sum_{i=1}^{r} a_i=\sum_{i=1}^{r} \sum_{j=1}^i d_j
∑i=1rai=∑i=1r∑j=1idj,可以将此式展开易发现每个
d
j
d_j
dj 出现了
r
−
j
+
1
r-j+1
r−j+1 次,所以上述式子可以进一步转化为
∑
i
=
1
r
d
i
×
(
r
−
i
+
1
)
=
(
r
+
1
)
∑
i
=
1
r
d
i
−
∑
i
=
1
r
i
×
d
i
\sum_{i=1}^r d_i\times (r-i+1) = (r+1)\sum_{i=1}^r d_i-\sum_{i=1}^ri\times d_i
∑i=1rdi×(r−i+1)=(r+1)∑i=1rdi−∑i=1ri×di
故
∑
i
=
1
r
d
i
\sum_{i=1}^r d_i
∑i=1rdi 和
∑
i
=
1
r
i
×
d
i
\sum_{i=1}^ri\times d_i
∑i=1ri×di 分别可以用 trd[] 和 trid[] 两个树状数组维护,每次查询其前缀和即可。而两个树状数组的单点修改:第一个数组trd[]就是例题2中常规的差分数组 trd[l] += val, trd[r+1] -= val,而后面一个不难发现增加或减少的值与下标相对应 trid[l] += l*val, trid[r+1] -= (r+1)*val
int n, m;
ll tr[maxn][maxn];intlowbit(int x){return x &-x;}voidupdate(int x,int y, ll val){for(int i = x; i <= n; i +=lowbit(i)){for(int j = y; j <= m; j +=lowbit(j)){
tr[i][j]+= val;}}}
ll sum(int x,int y){// tr[1][1] + ... + tr[x][y] 子矩阵和
ll res =0;for(int i = x; i >0; i -=lowbit(i)){for(int j = y; j >0; j -=lowbit(j)){
res += tr[i][j];}}return res;}
ll query(int sx,int sy,int tx,int ty){returnsum(tx, ty)-sum(sx -1, ty)-sum(tx, sy -1)+sum(sx -1, sy -1);}voidsolve(){
cin >> n >> m;int op;while(cin >> op){if(op ==1){int x, y;
ll val;
cin >> x >> y >> val;update(x, y, val);}else{int a,b,c,d;
cin >> a >> b >> c >> d;
cout <<query(a, b, c, d)<<"\n";}}}
int n, m;
ll t1[maxn][maxn], t2[maxn][maxn], t3[maxn][maxn], t4[maxn][maxn];intlowbit(int x){return x &-x;}voidupdate(int x,int y, ll val){for(int i = x; i <= n; i +=lowbit(i)){for(int j = y; j <= m; j +=lowbit(j)){
t1[i][j]+= val;
t2[i][j]+= val * x;
t3[i][j]+= val * y;
t4[i][j]+= val * x * y;}}}
ll query(int x,int y){// tr[1][1] + ... + tr[x][y]
ll res =0;for(int i = x; i >0; i -=lowbit(i)){for(int j = y; j >0; j -=lowbit(j)){
res += t1[i][j]*(x +1)*(y +1)- t2[i][j]*(y +1)- t3[i][j]*(x +1)+ t4[i][j];}}return res;}voidsolve(){
cin >> n >> m;int op;while(cin >> op){if(op ==1){int a, b, c, d;
ll k;
cin >> a >> b >> c >> d >> k;update(a, b, k);update(c +1, d +1, k);update(a, d +1,-k);update(c +1, b,-k);}else{int a, b, c, d;
cin >> a >> b >> c >> d;
cout <<query(c, d)-query(a -1, d)-query(c, b -1)+query(a -1, b -1)<<"\n";}}}