【数据结构】二维树状数组
【数据结构】二维树状数组
一、二维树状数组
二维树状数组,其实就是一维的树状数组上的节点再套个树状数组,就变成了二维树状数组了。
const int N = 1e3 + 10;
int tr[N][N], n, m;
#define lowbit(x) (x & -x)
void add(int x, int y, int d) {
for (int i = x; i <= n; i += lowbit(i))
for (int j = y; j <= m; j += lowbit(j))
tr[i][j] += d;
}
int query(int x, int y) {
int ret = 0;
for (int i = x; i; i -= lowbit(i))
for (int j = y; j; j -= lowbit(j))
ret += tr[i][j];
return ret;
}
二、单点修改,区间查询
给出一个 的零矩阵 ,你需要完成如下操作:
- :表示元素 _{ , } 自增
- : 表示询问左上角为 ,右下角为 的子矩阵内所有数的和

单点增加,因此可以直接加上就可以了
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 5000; // 2^(12)=4096
int n, m;
LL tr[N][N];
#define lowbit(x) (x & -x)
void add(int x, int y, int d) {
for (int i = x; i <= n; i += lowbit(i))
for (int j = y; j <= m; j += lowbit(j))
tr[i][j] += d;
}
LL query(int x, int y) {
LL ret = 0;
for (int i = x; i; i -= lowbit(i))
for (int j = y; j; j -= lowbit(j))
ret += tr[i][j];
return ret;
}
int main() {
//加快读入
ios::sync_with_stdio(false), cin.tie(0);
cin >> n >> m;
int opt;
while (cin >> opt) {
if (opt == 1) {
int x, y, d;
cin >> x >> y >> d;
add(x, y, d);
} else {
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
cout << query(x2, y2) - query(x1 - 1, y2) - query(x2, y1 - 1) + query(x1 - 1, y1 - 1) << '\n';
}
}
return 0;
}
三、区间修改,单点查询
给出一个 的零矩阵 ,你需要完成如下操作:
- :表示左上角为 ,右下角为 的子矩阵内所有数都自增加 ;
- :表示询问元素 的值。
只需要利用一个二维树状数组,维护一个二维差分数组,单点查询即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 5000;
int bit[N][N];
int n, m;
LL tr[N][N];
#define lowbit(x) (x & -x)
void add(int x, int y, int d) {
for (int i = x; i <= n; i += lowbit(i))
for (int j = y; j <= m; j += lowbit(j))
tr[i][j] += d;
}
LL query(int x, int y) {
LL ret = 0;
for (int i = x; i; i -= lowbit(i))
for (int j = y; j; j -= lowbit(j))
ret += tr[i][j];
return ret;
}
int main() {
//加快读入
ios::sync_with_stdio(false), cin.tie(0);
cin >> n >> m;
int op;
while (cin >> op) {
if (op == 1) {
int x1, y1, x2, y2, d;
cin >> x1 >> y1 >> x2 >> y2 >> d;
//二维差分
add(x1, y1, d);
add(x1, y2 + 1, -d);
add(x2 + 1, y1, -d);
add(x2 + 1, y2 + 1, d);
} else {
int x, y;
cin >> x >> y;
cout << query(x, y) << '\n';
}
}
return 0;
}
四、区间修改,区间查询
给定一个大小为 的零矩阵,直到输入文件结束,你需要进行若干个操作,操作有两类:
-
,表示将左上角为 ,右下角为 的子矩阵全部加上 ;
-
, 表示询问左上角为 ,右下角为 为顶点的子矩阵的所有数字之和。
考虑前缀和 和 原数组 , 差分数组 之间的关系。
首先 (二维前缀和)
双由于 (差分数组与原数组关系)
所以:
可以说是非常复杂了......
统计出现次数
-
从到全都要出现一次,所以有个,即
-
从到,出现了多少次呢?头脑中出现一个二维差分转原数组(本质就是一个原数组转二维前缀和)的图像:
- 时, 就没有出现
- 时, 出现次
- ...
- 时, 就没有出现
- 时, 出现次
- ...
总结一下:
等等……
所以我们不难把式子变成:
展开得到:
也就相当于把这个式子拆成了四个部分:
所以我们需要在原来 记录 的基础上,再添加三个树状数组:
记录
记录
] 记录
这样一来,就能通过数组的差分数组来得到的前缀和数组。
最后,易知到的矩阵和就是一个标准的二维前缀和公式,等于
代码模板
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2050;
int n, m;
LL C1[N][N], C2[N][N], C3[N][N], C4[N][N];
#define lowbit(x) (x & -x)
//维护四个树状数组
void add(int x, int y, int d) {
for (int i = x; i <= n; i += lowbit(i))
for (int j = y; j <= m; j += lowbit(j)) {
C1[i][j] += d;
C2[i][j] += d * x;
C3[i][j] += d * y;
C4[i][j] += d * x * y;
}
}
//查询左上角为(1,1)右下角为(x,y)的矩阵和
LL query(int x, int y) {
LL ret = 0;
for (int i = x; i > 0; i -= lowbit(i)) {
for (int j = y; j > 0; j -= lowbit(j)) {
ret += (x + 1) * (y + 1) * C1[i][j];
ret -= (y + 1) * C2[i][j];
ret -= (x + 1) * C3[i][j];
ret += C4[i][j];
}
}
return ret;
}
int main() {
//加快读入
ios::sync_with_stdio(false), cin.tie(0);
cin >> n >> m;
int op;
while (cin >> op) {
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
if (op == 1) {
int d;
cin >> d;
//维护四个数组
add(x1, y1, d);
add(x1, y2 + 1, -d);
add(x2 + 1, y1, -d);
add(x2 + 1, y2 + 1, d);
} else
cout << query(x2, y2) - query(x1 - 1, y2) - query(x2, y1 - 1) + query(x1 - 1, y1 - 1) << '\n';
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
2021-12-09 AcWing 1021. 货币系统
2021-12-09 AcWing 1023. 买书
2021-12-09 AcWing 278. 数字组合
2021-12-09 AcWing 1022. 宠物小精灵之收服
2021-12-09 AcWing 1024. 装箱问题
2021-12-09 AcWing 423. 采药
2017-12-09 为预热准备更新时间列的查询办法,解决原表中没有索引的问题