【BZOJ1513】【POI2006】Tet-Tetris 3D 二维线段树+标记永久化

题解:题意很裸啊~~~

培训的时候说要写标记永久化,反正永久化很水,就直接写了。

但是我并不知道为什么要永久化,或者说理解不深刻,但是再遇上肯定能分析出来233。

大概应该可能或许就是:

直接原因:下传标记传不下去。

根本原因:

线段树有两层,这样它的传递可能就有点像拓扑了

就是外层线段树需要往内层线段树传,然后内层线段树还要下传

这样扫到某处时发现,****,还需要顺着两边的标记路径回溯到根,

然后各种压栈啊什么的,才能传下去,而且大概率出错(代码错或思路错)。

所以简简单单写个标记永久化好了,(反正十分简单

蒟蒻可能说错了,欢迎大神 or 新星们留言批斥。

代码(短小精悍弱爆了):

(话说你们看到我的define N不要吐槽,它的数据范围可能略弱,我是从别人那里粘来的N~~~~~)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 705
using namespace std;
int n,m,q;
int h,x0,x1,y0,y1;
struct segment_Tree
{
	int val[N<<2],flag[N<<2];
	int query(int note=1,int L=1,int R=m,int l=y0,int r=y1)
	{
		if(L==l&&r==R)return val[note];
		int mid=L+R>>1,ans=flag[note];
		if(r<=mid)return max(ans,query(note<<1,L,mid,l,r));
		else if(l>mid)return max(ans,query(note<<1|1,mid+1,R,l,r));
		else return max(ans,max(query(note<<1,L,mid,l,mid),query(note<<1|1,mid+1,R,mid+1,r)));
	}
	void change(int note=1,int L=1,int R=m,int l=y0,int r=y1,int w=h)
	{
		val[note]=max(val[note],w);
		if(L==l&&r==R)
		{
			flag[note]=max(flag[note],w);
			return ;
		}
		int mid=L+R>>1;
		if(r<=mid)change(note<<1,L,mid,l,r);
		else if(l>mid)change(note<<1|1,mid+1,R,l,r);
		else change(note<<1,L,mid,l,mid),change(note<<1|1,mid+1,R,mid+1,r);
	}
};
struct Segment_Tree
{
	segment_Tree val[N<<2],flag[N<<2];
	int query(int note=1,int L=1,int R=n,int l=x0,int r=x1)
	{
		if(L==l&&r==R)return val[note].query();
		int mid=L+R>>1,ans=flag[note].query();
		if(r<=mid)return max(ans,query(note<<1,L,mid,l,r));
		else if(l>mid)return max(ans,query(note<<1|1,mid+1,R,l,r));
		else return max(ans,max(query(note<<1,L,mid,l,mid),query(note<<1|1,mid+1,R,mid+1,r)));
	}
	void change(int note=1,int L=1,int R=n,int l=x0,int r=x1,int w=h)
	{
		val[note].change();
		if(L==l&&r==R)
		{
			flag[note].change();
			return ;
		}
		int mid=L+R>>1;
		if(r<=mid)change(note<<1,L,mid,l,r);
		else if(l>mid)change(note<<1|1,mid+1,R,l,r);
		else change(note<<1,L,mid,l,mid),change(note<<1|1,mid+1,R,mid+1,r);
	}
}tree;
int main()
{
//	freopen("test.in","r",stdin);

	scanf("%d%d%d",&n,&m,&q);
	while(q--)
	{
		scanf("%d%d%d%d%d",&x1,&y1,&h,&x0,&y0);
		x1+=x0,y1+=y0,x0++,y0++;
		h+=tree.query();
		tree.change();
	}
	x0=y0=1,x1=n,y1=m;
	printf("%d\n",tree.query(1,1,n,1,n));
	return 0;
}
时间: 2024-10-25 01:08:38

【BZOJ1513】【POI2006】Tet-Tetris 3D 二维线段树+标记永久化的相关文章

POJ 2155 Matrix 二维线段树+标记永久化?

题意:链接 方法:二维线段树+标记永久化 解析:题意是比较明朗的,算一下内存发现4000^2也是可以接受的,于是就开始yy二维线段树? 对于第一层x的线段树,每个节点开一整棵y线段树. 用个二维数组就实现了? 不过发现个问题啊,这题怎么pushdown啊,标记传不下去啊.如果给x打个标记那么怎么知道y传那段啊? 于是就学了新的东西?标记永久化. 本题是单点查询嘛,标记永久化就应该是把相应的区间直接异或,不用往下传?那查询的时候怎么办呢?只需要在查询的时候把所有路过该点的区间都异或起来就OK了.貌

【BZOJ1513】[POI2006]Tet-Tetris 3D 二维线段树

[BZOJ1513][POI2006]Tet-Tetris 3D Description Task: Tetris 3D "Tetris" 游戏的作者决定做一个新的游戏, 一个三维的版本, 在里面很多立方体落在平面板,一个立方体开始落下直到碰上一个以前落下的立方体或者落地即停止. 作者想改变一下游戏的目的使得它更大众化,在新游戏中你将知道落下的立方体信息以及位置,你的任务就是回答所有立方体落下后最高的方块的高度.所有的立方体在下落过程中都是垂直的并且不会旋转.平板左下角坐标为原点,并且

BZOJ 1513 POI2006 Tet-Tetris 3D 二维线段树

题目大意:给定一个矩阵,初始每个位置上的元素都是0,每次选择一个子矩形,将这个子矩形内的值修改为这个子矩形内的最大值+h,求最终所有位置上的最大值 我们需要维护一种数据结构,支持更新子矩形的值和查询子矩形最大值 似乎二维线段树就可以了? 但是YY了一下我们会发现两个没法解决的问题: 1.标记的下传 2.信息的上传 其实... 第一个很好办嘛!不下传不就好了! 标记永久化,无需下传,只要查询的时候对线段树路径上的每一个点都询问一遍就行了! 那么第二个呢? 第二个很好办嘛!不上传不就好了! 由于修改

BZOJ 1513 POI 2006 Tet-Tetris 3D 二维线段树

题目大意:三维俄罗斯方块,问最后摞了多高. 思路:二维线段树的裸题.但是要注意二维线段树不支持标记下穿.所以就不下传,每次更新答案的时候先看标记,然后用所有的跟标记比较大小之后返回. 具体看代码吧,不知道怎么说. CODE: #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define

HDU1832 二维线段树求最值(模板)

Luck and Love Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 50 Accepted Submission(s): 20   Problem Description 世界上上最远的距离不是相隔天涯海角而是我在你面前可你却不知道我爱你                ―― 张小娴 前段日子,枫冰叶子给Wiskey做了个征婚启事,聘

ZOJ 2859 二维线段树

思路:自己写的第二发二维线段树1A,哈哈,看来对二维的push操作比较了解了:但是还没遇到在两个线段树中同时进行push操作的,其实这题我是想在x维和y维同时进行push操作的,但是想了好久不会,然后看到这题又给出10秒,然后想想在x维线段直接单点查询肯定也过了,然后在第二维就只有pushup操作,在第一维线段树没有pushup操作.要是在第一维也有pushup操作的话,那就不用单点查询那么慢了.不过也A了,想找题即在二维同时进行pushup和pushdown操作的. #include<iost

[POJ2155] Matrix(二维线段树,树套树)

题目链接:http://poj.org/problem?id=2155 题意:给一个01矩阵,两个操作,翻转:子矩阵里每一个数都由0变1,1变0. 查询:查询某一点是0还是1. 一直以为二维线段树就是开一个线段树数组的我- 这题暴力更新每一个小矩形,翻转就+1,最后看看某点的奇偶. 写屎了,特别注意的是在外层查询的时候要先把当前层的内层query掉,接着再向下扩展.这样外层就不用lazy啦 1 #include <algorithm> 2 #include <iostream> 3

poj1195 Mobile phones 二维线段树入门

二维线段树就是树套树,线段树套线段树... #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) #define lson l,m,rt<<1 #

UVA 11297 Census ——二维线段树

[题目分析] 二维线段树模板题目. 简直就是无比的暴力.时间复杂度为两个log. 标记的更新方式比较奇特,空间复杂度为N^2. 模板题目. [代码] #include <cstdio> #include <cstring> //#include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #include <str