二维线段树(线段树套线段树)
模板题
解析
先转化一下,发现每次放一个立方体,就是对一个二维平面赋值,最后查询其实就是查询二维平面的最大值。
本体强制在线,所以就要用到我们的二维线段树。
刚开始学树套树的时候很容易因为什么对外层建一棵树,对内层建一棵树而懵逼,但是其实写一下就能搞懂了。
我们对 \(x\) 轴维护一颗线段树,线段树的每个节点存一棵线段树,那么比如我们访问到了外层的一个节点,那么这个节点的左右端点就表示矩形最左和最右的点的横坐标,我们在这个节点保存的线段树中维护 \(y\) 轴的信息,同样的,当我们访问到了内存的某个节点时,它的左右端点就表示矩形最上和最下的点的纵坐标。那这样一个矩形的是不是就被我们表示出来啦?所以我们将信息保存到这两个节点里面,是不是就能维护一个矩形的信息了?
具体方法就像上文所述,现在外层线段树中找到左右横坐标在矩形内部的,然后在内层线段树中找到上下纵坐标在矩形内部的,然后维护信息就好了。
注意点
不过线段树套线段树的如果有区间修改的话必须使用标记永久化。
并且我们将二维平面的点转成方格之后,矩形的另外两个角的坐标有所变化哦。
内层线段树封装起来体验感超好。
双倍经验
代码
#include<cstdio>
#include<cctype>
#include<iostream>
using namespace std;
#define re register
const int N = 2050;
int n, m, q;
class SegmentTree {
private :
struct SWC {
int Max[N], tag[N];
void update(int p, int l, int r, int L, int R, int k) {
Max[p] = max(Max[p], k);
if(l == L && r == R) {
tag[p] = max(tag[p], k);
return ;
}
re int mid = (l + r) >> 1;
if(R <= mid) return update(p << 1, l, mid, L, R, k);
if(L > mid) return update(p << 1 | 1, mid + 1, r, L, R, k);
update(p << 1, l, mid, L, mid, k), update(p << 1 | 1, mid + 1, r, mid + 1, R, k);
}
int query(int p, int l, int r, int L, int R) {
if(l == L && r == R) return Max[p];
re int ans = tag[p], mid = (l + r) >> 1;
if(R <= mid) return max(ans, query(p << 1, l, mid, L, R));
if(L > mid) return max(ans, query(p << 1 | 1, mid + 1, r, L, R));
return max(ans, max(query(p << 1, l, mid, L, mid), query(p << 1 | 1, mid + 1, r, mid + 1, R)));
}
};
public :
SWC Max[N], tag[N];
void update(int p, int l, int r, int u, int d, int L, int R, int k) {
Max[p].update(1, 1, m, u, d, k);
if(l == L && r == R) return tag[p].update(1, 1, m, u, d, k);
re int mid = (l + r) >> 1;
if(R <= mid) return update(p << 1, l, mid, u, d, L, R, k);
if(L > mid) return update(p << 1 | 1, mid + 1, r, u, d, L, R, k);
update(p << 1, l, mid, u, d, L, mid, k), update(p << 1 | 1, mid + 1, r, u, d, mid + 1, R, k);
}
int query(int p, int l, int r, int u, int d, int L, int R) {
if(l == L && r == R) return Max[p].query(1, 1, m, u, d);
re int ans = tag[p].query(1, 1, m, u, d), mid = (l + r) >> 1;
if(R <= mid) return max(ans, query(p << 1, l, mid, u, d, L, R));
if(L > mid) return max(ans, query(p << 1 | 1, mid + 1, r, u, d, L, R));
return max(ans, max(query(p << 1, l, mid, u, d, L, mid), query(p << 1 | 1, mid + 1, r, u, d, mid + 1, R)));
}
}tr;
inline void read(int &x) {
x = 0; int c = getchar();
for(; !isdigit(c); c = getchar());
for(; isdigit(c); c = getchar())
x = x * 10 + c - 48;
}
int main() {
read(n), read(m), read(q);
for(re int i = 1, d, s, h, x, y; i <= q; i++) {
read(d), read(s), read(h), read(x), read(y);
tr.update(1, 1, n, y + 1, y + s, x + 1, x + d, tr.query(1, 1, n, y + 1, y + s, x + 1, x + d) + h);
}
printf("%d\n", tr.query(1, 1, n, 1, m, 1, n));
return 0;
}

浙公网安备 33010602011771号