【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;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值