SP1741 TETRIS3D - Tetris 3D
“俄罗斯方块”的作者决定制作一个3D版本的“俄罗斯方块”。有若干个长方体积木,它们将以一定的顺序下落,最底端是一个矩形平台。积木停止下落当且仅当它碰到了矩形平台或另一个已经停止下落的积木。它将保持这个位置不变直至游戏结束。
然而作者想要改变这个游戏的玩法。已知积木的下降顺序以及积木的起始释放位置,求游戏结束后积木堆最高点的高度。假设积木竖直下落且不旋转。为了描述方便起见,我们引入一个笛卡尔坐标系,原点为平台的顶点,轴与平台边缘平行。
题意:初始矩形为\(0\),每次将一个子矩形修改为这个子矩形的最大值\(+h\)
首先我们对\(x\)轴建线段树(称为内层),然后在内层的基础上,对\(y\)轴建线段树(称为外层)
那么外层的操作都是在其对应的内层的基础上完成的
既然是线段树,那么我们思考这样一个问题,如何区间加
对于内层而言,可以打\(lazytag\)并进行\(pushdown\),\(pushup\)也是可以进行的
然而对于外层,因为每个子节点我们维护的信息太多了,所以内层的\(pushdown\)和\(pushup\)都无法进行
于是我们另辟蹊径:标记永久化
我们多维护一个\(tag\)值,表示这个区间修改后的值
当我们修改的时候,都是可以用修改的值\(val\)去更新该区间的最大值\(max\)
而只有这个区间完全被覆盖时我们才用\(val\)去个更新\(tag\)
这个标记是对于子区间也是有效的,所以询问的时候要拿出这个区间的\(tag\)去尝试更新答案
语言太无力了,还是上代码吧qwq
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#define N 50000
#define M 2500
#define zrt k << 1
#define yrt k << 1 | 1
using namespace std;
int n,m,q;
struct node
{
int ma,tag;
};
struct SegX
{
node s[M + 5];
void change(int k,int l,int r,int x,int y,int z)
{
s[k].ma = max(s[k].ma,z);
if (l == x && r == y)
{
s[k].tag = max(s[k].tag,z);
return;
}
int mid = l + r >> 1;
if (x > mid)
change(yrt,mid + 1,r,max(x,mid + 1),y,z);
else
if (y <= mid)
change(zrt,l,mid,x,min(y,mid),z);
else
change(zrt,l,mid,x,min(y,mid),z),change(yrt,mid + 1,r,max(x,mid + 1),y,z);
}
int query(int k,int l,int r,int x,int y)
{
if (l == x && r == y)
return s[k].ma;
int mid = l + r >> 1;
if (x > mid)
return max(query(yrt,mid + 1,r,max(x,mid + 1),y),s[k].tag);
else
if (y <= mid)
return max(query(zrt,l,mid,x,min(y,mid)),s[k].tag);
else
return max(s[k].tag,max(query(zrt,l,mid,x,min(y,mid)),query(yrt,mid + 1,r,max(x,mid + 1),y)));
}
};
struct SegY
{
SegX s[M + 5],tag[M + 5];
void change(int k,int l,int r,int xl,int xr,int yl,int yr,int z)
{
s[k].change(1,1,n,xl,xr,z);
if (l == yl && r == yr)
{
tag[k].change(1,1,n,xl,xr,z);
return;
}
int mid = l + r >> 1;
if (yl > mid)
change(yrt,mid + 1,r,xl,xr,max(yl,mid + 1),yr,z);
else
if (yr <= mid)
change(zrt,l,mid,xl,xr,yl,min(yr,mid),z);
else
change(zrt,l,mid,xl,xr,yl,min(yr,mid),z),change(yrt,mid + 1,r,xl,xr,max(yl,mid + 1),yr,z);
}
int query(int k,int l,int r,int xl,int xr,int yl,int yr)
{
if (l == yl && r == yr)
return s[k].query(1,1,n,xl,xr);
int mid = l + r >> 1,ans = tag[k].query(1,1,n,xl,xr);
if (yl > mid)
return max(ans,query(yrt,mid + 1,r,xl,xr,max(yl,mid + 1),yr));
else
if (yr <= mid)
return max(ans,query(zrt,l,mid,xl,xr,yl,min(yr,mid)));
else
return max(ans,max(query(zrt,l,mid,xl,xr,yl,min(yr,mid)),query(yrt,mid + 1,r,xl,xr,max(yl,mid + 1),yr)));
}
}tree;
int main()
{
scanf("%d%d%d",&n,&m,&q);
int d,s,h,x,y,z;
for (int i = 1;i <= q;i++)
{
scanf("%d%d%d%d%d",&d,&s,&h,&x,&y);
z = tree.query(1,1,m,x + 1,x + d,y + 1,y + s);
tree.change(1,1,m,x + 1,x + d,y + 1,y + s,z + h);
}
printf("%d\n",tree.query(1,1,m,1,n,1,m));
return 0;
}