二维线段树
1.算法分析
对于二维的线段树,有2种写法,分别为四叉树写法和树套树写法:
1.1 四叉树写法
参照一维线段树的写法:每次将区间二分成两个子区间,对应矩阵应对X,Y同时二分,也就是4个子矩阵,即左上、右上、左下,右下四部分,所以要建一颗四叉树,如果当前矩阵为一维时,只需二分成两个子区间。具体写法和一维线段树类似,可以查看代码
1.2 树套树写法
树套树指的是线段树套线段树,现在x轴建立一颗线段树,然后在每个节点上面再建立一颗y轴的线段树。这样无论是查询还是修改,先找到x轴的线段树节点,然后再在y轴的线段树上进行修改或者查找即可。
2.模板
参考:https://blog.csdn.net/u012469987/article/details/47341457
2.1 四叉树写法:单点修改,区间询问
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e3 + 13;
int n, m, x, y, L, T, q, a[MAXN][MAXN];
struct tree {
int x1, y1, x2, y2;
int Max, Min;
} tr[MAXN * MAXN * 4];
int son(int p, int x) {
return p * 4 - 2 + x; }
void pushup1(int rt) {
tr[rt].Max = max(tr[son(rt, 0)].Max, tr[son(rt, 1)].Max);
tr[rt].Min = min(tr[son(rt, 0)].Min, tr[son(rt, 1)].Min);
for (int i = 2; i < 4; ++i) {
tr[rt].Max = max(tr[rt].Max, tr[son(rt, i)].Max);
tr[rt].Min = min(tr[rt].Min, tr[son(rt, i)].Min);
}
}
void pushup2(int rt) {
//二叉树的pushup
tr[rt].Max = max(tr[son(rt, 0)].Max, tr[son(rt, 1)].Max);
tr[rt].Min = min(tr[son(rt, 0)].Min, tr[son(rt, 1)].Min);
}
void build(int rt, int X1, int Y1, int X2, int Y2) {
tr[rt].x1 = X1, tr[rt].x2 = X2;
tr[rt].y1 = Y1, tr[rt].y2 = Y2;
if (X1 == X2 && Y1 == Y2) {
tr[rt].Max = a[X1][Y1];
tr[rt].Min = a[X1][Y1];
return;
}
int midx = (X1 + X2) >> 1;
int midy = (Y1 + Y2) >> 1;
if (X1 == X2) {
build(son(rt, 0), X1, Y1, X2, midy);
build(son(rt, 1), X1, midy + 1, X2, Y2);
pushup2(rt);
} else if (Y1 == Y2) {
build(son(rt, 0), X1, Y1, midx, Y2);
build(son(rt, 1), midx + 1, Y1, X2, Y2);
pushup2(rt);
} else {
build(son(rt, 0), X1, Y1, midx, midy);
build(son(rt, 1), midx + 1, Y1, X2, midy);
build(son(rt, 2), X1, midy + 1, midx, Y2);
build(son(rt, 3), midx + 1, midy + 1, X2, Y2);
pushup1(rt);
}
}
int A, B;
void query(int rt, int X1, int Y1, int X2, int Y2) {
if (tr[rt].x1 > X2 || tr[rt].x2 < X1 || tr[rt].y1 > Y2 || tr[rt].y2 < Y1)
return;
if (tr[rt].x1 >= X1 && tr[rt].x2 <= X2 && tr[rt].y1 >= Y1 && tr[rt].y2 <= Y2) {
A = max(A, tr[rt].Max);
B = min(B, tr[rt].Min);
return;
}
if (tr[rt].x1 == tr[rt].x2 || tr[rt].y1 == tr[rt].y2) {
query(son(rt, 0), X1, Y1, X2, Y2);
query(son(rt, 1), X1, Y1, X2, Y2);
} else {
query(son(rt, 0), X1, Y1, X2, Y2);
query(son(rt, 1), X1, Y1, X2, Y2);
query(son(rt, 2), X1, Y1, X2, Y2);
query(son(rt, 3), X1, Y1, X2, Y2);
}
}
void modify(int rt, int X1, int Y1, int X2, int Y2, int val) {
if (tr[rt].x1 > X2 || tr[rt].x2 < X1 || tr[rt].y1 > Y2 || tr[rt].y2 < Y1)
return;
if (tr[rt].x1 >= X1 && tr[rt].x2 <= X2 && tr[rt].y1 >= Y1 && tr[rt].y2 <= Y2) {
tr[rt].Max = val;
tr[rt].Min = val;
return;
}
if (tr[rt].x1 == tr[rt].x2 || tr[rt].y1 == tr[rt].y2) {
modify(son(rt, 0), X1, Y1, X2, Y2, val);
modify(son(rt, 1), X1, Y1, X2, Y2, val);
pushup2(rt);
} else {
modify(son(rt, 0), X1, Y1, X2, Y2, val);
modify(son(rt, 1), X1, Y1, X2, Y2, val);
modify(son(rt, 2), X1, Y1, X2, Y2, val);
modify(son(rt, 3), X1, Y1, X2, Y2, val);
pushup1(rt);
}
}
int main() {
scanf("%d", &T);
for (int i = 1; i <= T; ++i) {
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j) scanf("%d", &a[i][j]);
build(1, 1, 1, n, n); // 建树
scanf("%d", &q);
printf("Case #%d:\n", i);
int X1, X2, Y1, Y2;
while (q--) {
scanf("%d %d %d", &x, &y, &L);
L = (L - 1) >> 1;
X1 = max(1, x - L), Y1 = max(1, y - L); // 找到边界
X2 = min(n, x + L), Y2 = min(n, y + L);
A = 0, B = 1e9 + 19;
query(1, X1, Y1, X2, Y2); //区间查询
modify(1, x, y, x, y, (A + B) >> 1); // 单点修改
printf("%d\n", (A + B) >> 1);
}
}
return 0;
}
2.2 树套树写法:单点修改,区间询问
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
typedef long long LL;
using namespace std;
const int MAXN = 1025;
LL sum[MAXN * 4][MAXN * 4];
int n;
void subBuild(int rt, int l, int r, int x) {
sum[x][rt] = 0;
if (l != r) {
int m = (l + r) >> 1;
subBuild(rt << 1, l, m, x);
subBuild(rt << 1 | 1, m + 1, r, x);
}
}
void build(int rt, int l, int r) {
subBuild(1, 1, n, rt);
if (l != r) {
int m = (l + r) >> 1;
build(rt << 1, l, m);
build(rt << 1 | 1, m + 1, r);
}
}
void subUpdate(int rt, int l, int r, int x, int Y, int num) {
if (l == r && r == Y) {
sum[x][rt] += num;
} else {
int m = (l + r) >> 1;
if (Y <= m) subUpdate(rt << 1, l, m, x, Y, num);
if (Y > m) subUpdate(rt &