(请先复习单点修改,区间求和以及利用差分实现区间修改,单点求和)
区间修改,区间求和(CodeVs-BIT模版)
控制两个树状数组A,B
Add操作(r, k):[1,r]加上k (注意,从l加到r就可以先Add(r,k)再Add(l-1, -k))
Add时,A[r]+=k,B[r]+=k*r
Query操作(r):查询[1,r]的和
Query时,结果就是B[1]~B[n] + r * (A[r+1]~A[n]) (请自行思考)
这两个累加就用两个树状数组.
#include <iostream>
using namespace std;
typedef long long LL;
LL A[200010], B[200010];
int n, q;
inline int lowbit(int x) {
return x & (-x);
}
LL Query1(int k) {
LL ans = 0;
for(int i=k; i; i-=lowbit(i)) ans += A[i];
return ans;
}
LL Query2(int k) {
LL ans = 0;
for(int i=k; i; i-=lowbit(i)) ans += B[i];
return ans;
}
void Add1(int k, LL x) {
for(int i=k; i<=n; i+=lowbit(i)) A[i] += x;
}
void Add2(int k, LL x) {
for(int i=k; i<=n; i+=lowbit(i)) B[i] += x;
}
void Add(int r, int x) { //区间修改
if(!r) return;
Add1(r, x);
Add2(r, r*x);
}
LL Query(int r) { //区间询问
return Query2(r) + r * (Query1(n) - Query1(r));
}
int main() {
LL x;
cin >> n;
for(int i=1; i<=n; i++) {
cin >> x;
Add(i, x);
Add(i-1, -x);
}
cin >> q;
for(int i=1; i<=q; i++) {
int opt, l, r;
LL k;
cin >> opt;
if(opt == 1) {
cin >> l >> r >> k;
Add(r, k);
Add(l-1, -k);
} else if(opt == 2) {
cin >> l >> r;
cout << Query(r) - Query(l-1) << endl;
}
}
return 0;
}
二维矩阵:单点修改,矩形求和
树状数组的维度拓展非常简单,即“数组多一维,循环多一层“
下面是询问操作和修改操作
int Query(int i, int j) {
int ans = 0;
for(; i; i-=lowbit(i))
for(; j; j-=lowbit(i))
ans += B[i][j];
return ans;
}
void Add(int i, int j, int x) {
for(; i<=n; i+=lowbit(i))
for(; j<=m; j+=lowbit(j))
B[i][j] += x;
}
而对于非前缀矩形,可以拆成一个比较大大矩形减去两个前缀矩形再加上一个小的重合部分的前缀矩形
(可以自行画图理解)
二维矩阵:矩形修改,矩形求和
写四个二维BIT即可