[POI2006] TET-Tetris 3D

发布时间 2023-09-10 18:15:10作者: 徐子洋

题目链接1题目链接2

注意到这道题本质就是一个矩形求和矩形赋值的操作。其中满足:对于任意一个点,每次赋予的权值是单调递增的。

这看起但就像是一个二维线段树能做的范畴。但是众所周知,二维线段树的外层无法进行标记上传操作(无法 pushup),故而这题我们考虑标记永久化。同时,为了简化问题,我们先关心一维的情况。

我们考虑对于每个点,记录两个权值:\(mx\)\(tg\)。前者为当前区间的最大值,后者为标记值。

  • 对于修改操作。沿用常规的懒标记线段树的方法,更新那些被当前区间完全包含的极大区间的 \(tg\) 值。同时,更新修改过程中遍历到过的所有节点的 \(mx\)
  • 对于询问操作,进行标记永久化的查询。同时,对于那些被当前区间完全包含的极大区间,我们也拿它的 \(mx\) 值区更新答案。

二维情况类似。

点击查看代码
#include <bits/stdc++.h>
#define FL(i, a, b) for(int i = (a); i <= (b); i++)
#define FR(i, a, b) for(int i = (a); i >= (b); i--)
using namespace std;
int D, S, N;
namespace T{
	struct SGTx{
		int mx[2050], tg[2050];
		void Upd(int p, int l, int r, int x, int y, int v){
			mx[p] = max(mx[p], v);
			if(x <= l && r <= y){tg[p] = max(tg[p], v); return;}
			int mid = l + r >> 1;
			if(x <= mid) Upd(p << 1, l, mid, x, y, v);
			if(mid < y) Upd(p << 1 | 1, mid + 1, r, x, y, v);
		}
		int Qry(int p, int l, int r, int x, int y){
			if(x <= l && r <= y) return mx[p];
			int mid = l + r >> 1, ret = tg[p];
			if(x <= mid) ret = max(ret, Qry(p << 1, l, mid, x, y));
			if(mid < y) ret = max(ret, Qry(p << 1 | 1, mid + 1, r, x, y));
			return ret;
		}
	} mx[2050], tg[2050];
	void Upd(int p, int l, int r, int x1, int y1, int x2, int y2, int v){
		mx[p].Upd(1, 1, S, x2, y2, v);
		if(x1 <= l && r <= y1){tg[p].Upd(1, 1, S, x2, y2, v); return;}
		int mid = l + r >> 1;
		if(x1 <= mid) Upd(p << 1, l, mid, x1, y1, x2, y2, v);
		if(mid < y1) Upd(p << 1 | 1, mid + 1, r, x1, y1, x2, y2, v);
	}
	int Qry(int p, int l, int r, int x1, int y1, int x2, int y2){
		if(x1 <= l && r <= y1) return mx[p].Qry(1, 1, S, x2, y2);
		int mid = l + r >> 1, ret = tg[p].Qry(1, 1, S, x2, y2);
		if(x1 <= mid) ret = max(ret, Qry(p << 1, l, mid, x1, y1, x2, y2));
		if(mid < y1) ret = max(ret, Qry(p << 1 | 1, mid + 1, r, x1, y1, x2, y2));
		return ret;
	}
}
int main(){
	scanf("%d%d%d", &D, &S, &N), D++, S++;
	FL(i, 1, N){
		int d, s, w, x, y, h;
		scanf("%d%d%d%d%d", &d, &s, &w, &x, &y), x++, y++;
		h = T::Qry(1, 1, D, x, x + d - 1, y, y + s - 1);
		T::Upd(1, 1, D, x, x + d - 1, y, y + s - 1, h + w);
	}
	printf("%d\n", T::Qry(1, 1, D, 1, D, 1, S));
	return 0;
}