二维线段树

例题

P3437 [POI2006]TET-Tetris 3D
最近,有人发明了一种三维版的俄罗斯方块。和二维版本类似,一些立方体按照一定的顺序掉落,直到碰到别的方块或是地面才会停止掉落。立方体停止掉落后会一直保持掉落时的位置,直到游戏结束。
你的朋友决定以这个新版本的俄罗斯方块为背景,出一道题。给出每个立方体的掉落顺序和其掉落的轨迹,在所有方块完成掉落后求出最高方块的高度。在这个游戏中,方块均垂直下落,且方块不会旋转或翻转。为了方便描述,我们会建立一个空间直角坐标系,该坐标系的原点为地面的一角,并且坐标轴与地面边缘平行。
现在轮到你解决这个问题了。

输入格式

第一行三个整数 D,S,ND,S,ND,S,N,分别为地面的长度,宽度,和将要掉落的立方体数量。
接下来 N 行,每行五个整数 \(d_i,s_i,w_i,x_i,y_i\)​,描述一个掉落的立方体。其中 \(d_i,s_i,w_i\)​ 分别代表立方体的长,宽,高。立方体的底面(即长 \(\times\) 宽的那一面)将正对地面。立方体底面四个角在地面的投影坐标分别为 \((x_i,y_i),(x_i+d_i,y_i),(x_i,y_i+s_i),(x_i+d_i,y_i+s_i)\)

输出格式

输出一个整数,即方块掉落结束后最高方块的高度。

数据范围

\(1 \leq N \leq 20000,1 \leq D,S \leq 1000,d_i,s_i \geq 1, 1 \leq w_i \leq 100000,0 \leq x_i,d_i+x_i \leq D, 0 \leq y_i,s_i+y_i \leq S\)

解析

线段树套线段树。
对于内层线段树,每个节点存两个值 mx、tag。mx 代表当前区间的最大值,tag 是永久化标记,表示对整个区间所做的修改,对于所有的子区间都有效。
对于外层线段树,每个节点开两个内层线段树mx、tag,定义同上。
其实这题最好动态开点。

代码

#include<cstdio>
#include<iostream>
using namespace std;

const int MAXN = 1e3 + 500;

int d, s, n;

struct segn {
	int mx[MAXN << 1], tag[MAXN << 1];
	void modify(int now, int l, int r, int lf, int rg, int val) {
		mx[now] = max(mx[now], val);
		if(l == lf && r == rg) {
			tag[now] = max(tag[now], val);
			return ;
		}
		int mid = (l + r) >> 1;
		if(rg <= mid) modify(now << 1, l, mid, lf, rg, val);
		else if(lf > mid) modify(now << 1 | 1, mid + 1, r, lf, rg, val);
		else modify(now << 1, l, mid, lf, mid, val), modify(now << 1 | 1, mid + 1, r, mid + 1, rg, val);
	}
	int query(int now, int l, int r, int lf, int rg) {
		if(l == lf && r == rg) return mx[now];
		int mid = (l + r) >> 1, res = tag[now];
		if(rg <= mid) res = max(res, query(now << 1, l, mid, lf, rg));
		else if(lf > mid) res = max(res, query(now << 1 | 1, mid + 1, r, lf, rg));
		else {
			res = max(res, query(now << 1, l, mid, lf, mid));
			res = max(res, query(now << 1 | 1, mid + 1, r, mid + 1, rg));
		}
		return res;
	}
};

struct segw {
	segn mx, tag;
}tr[MAXN << 1];

void change(int now, int lf, int rg, int l, int r, int ll, int rr, int val) {
	tr[now].mx.modify(1, 1, s, ll, rr, val);
	if(lf == l && rg == r) return tr[now].tag.modify(1, 1, s, ll, rr, val), void();
	int mid = (lf + rg) >> 1;
	if(r <= mid) change(now << 1, lf, mid, l, r, ll, rr, val);
	else if(l > mid) change(now << 1 | 1, mid + 1, rg, l, r, ll, rr, val);
	else {
		change(now << 1, lf, mid, l, mid, ll, rr, val);
		change(now << 1 | 1, mid + 1, rg, mid + 1, r, ll, rr, val);
	}
}

int getval(int now, int lf, int rg, int l, int r, int ll, int rr) {
	if(lf == l && rg == r) return tr[now].mx.query(1, 1, s, ll, rr);
	int mid = (lf + rg) >> 1, res = tr[now].tag.query(1, 1, s, ll, rr);
	if(r <= mid) res = max(res, getval(now << 1, lf, mid, l, r, ll, rr));
	else if(l > mid) res = max(res, getval(now << 1 | 1, mid + 1, rg, l, r, ll, rr));
	else {
		res = max(res, getval(now << 1, lf, mid, l, mid, ll, rr));
		res = max(res, getval(now << 1 | 1, mid + 1, rg, mid + 1, r, ll, rr));
	}
	return res;
}

int main() {
	scanf("%d%d%d",&d, &s, &n);
	int a, b, c, x, y;
	for(int i = 1; i <= n; i++) {
		scanf("%d%d%d%d%d",&a, &b, &c, &x, &y);
		++x; ++y;
		int h = getval(1, 1, d, x, x + a - 1, y, y + b - 1);
		change(1, 1, d, x, x + a - 1, y, y + b - 1, h + c);
	}
	printf("%d\n",getval(1, 1, d, 1, d, 1, s));
	return 0;
}
posted @ 2021-09-10 21:31  zym417  阅读(71)  评论(0编辑  收藏  举报