写一个数据结构, 维护一个n*n矩阵, 支持单点修改, 子矩阵最值查询. (n ≤ 100) 所谓二维线段树就是先按行建线段树 (x树) , 每个结点[x1, x2]是一棵按列建的线段树 (y树), 其中[y1, y2]表示y1~y2列, 行x1~x2的信息. 也就是说, 把x1~x2行同一列的信息压为一个数.
代码会有点长, 因为要写两个build
, 两个query
, 两个modify
.
query
: 在x树中分解区间, 查询分解出来的y树. y树的写法和一维线段树相同.modify
: 在x树中找到对应的行, 修改该行的y树. x树中真包含该行的结点也需要修改, 由两个子区间的y树合并得到. 也可以仅在叶子处合并, 非叶子结点像普通一维线段树一样处理.build
: 和modify
相似, 只是不在x树中定位某个特定的点.
合并信息可以重载运算符 (比如+号), 使代码简洁. 引入bits/stdc++.h
之后, y1
会和cmath
里的y1
冲突, 所以需要define
一下. 需要传的参数挺多, 虽然消灭全局变量比较安全......那就把它们装到namespace
里.
#include <bits/stdc++.h>
#define For(i, a, b) for (int i = (a), i##_ = (b); i <= i##_; ++i)
#define y1 y1_
using namespace std;
const int N = 500, inf = 1e9 + 1;
int n, a[N+1][N+1];
namespace S {
struct Data {
int mn, mx;
Data(int mn=inf, int mx=-1): mn(mn), mx(mx) {}
Data operator+(const Data& d)
{
return Data(min(mn, d.mn), max(mx, d.mx));
}
} d[4*N][4*N], ans;
int x, y, x1, y1, x2, y2;
void build_c(Data* D, int o, int l, int r, Data* L=0, Data* R=0)
{
if (l == r)
D[o] = L ? L[o] + R[o] : Data(a[x][l], a[x][l]);
else {
int m = (l+r)/2;
build_c(D, o*2, l, m, L, R);
build_c(D, o*2+1, m+1, r, L, R);
D[o] = D[o*2] + D[o*2+1];
}
}
void build_r(int o, int l, int r)
{
if (l == r)
x = l, build_c(d[o], 1, 1, n);
else {
int m = (l+r)/2;
build_r(o*2, l, m);
build_r(o*2+1, m+1, r);
build_c(d[o], 1, 1, n, d[o*2], d[o*2+1]);
}
}
void query_c(Data* D, int o, int l, int r)
{
if (y1 <= l && r <= y2)
ans = ans + D[o];
else {
int m = (l+r)/2;
if (y1 <= m)
query_c(D, o*2, l, m);
if (y2 > m)
query_c(D, o*2+1, m+1, r);
}
}
void query_r(int o, int l, int r)
{
if (x1 <= l && r <= x2)
query_c(d[o], 1, 1, n);
else {
int m = (l+r)/2;
if (x1 <= m)
query_r(o*2, l, m);
if (x2 > m)
query_r(o*2+1, m+1, r);
}
}
void modify_c(Data* D, int o, int l, int r, Data* L=0, Data* R=0)
{
if (l == r)
D[o] = L ? L[o] + R[o] : Data(a[x][y], a[x][y]);
else {
int m = (l+r)/2;
if (y <= m)
modify_c(D, o*2, l, m, L, R);
else
modify_c(D, o*2+1, m+1, r, L, R);
D[o] = D[o*2] + D[o*2+1];
}
}
void modify_r(int o, int l, int r)
{
if (l == r)
modify_c(d[o], 1, 1, n);
else {
int m = (l+r)/2;
if (x <= m)
modify_r(o*2, l, m);
else
modify_r(o*2+1, m+1, r);
modify_c(d[o], 1, 1, n, d[o*2], d[o*2+1]);
}
}
}
int main()
{
using namespace S;
scanf("%d", &n);
For (i, 1, n) For (j, 1, n) scanf("%d", &a[i][j]);
build_r(1, 1, n);
int q;
scanf("%d", &q);
while (q--) {
char op;
int v;
scanf(" %c", &op);
if (op == 'q') {
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
ans = Data();
query_r(1, 1, n);
printf("%d %d\n", ans.mx, ans.mn);
} else {
scanf("%d%d%d", &x, &y, &v);
a[x][y] = v;
modify_r(1, 1, n);
}
}
return 0;
}