BZOJ1513: [POI2006]Tet-Tetris 3D

题目大意:在一个给定的矩形区域内,每次查询一个矩形的最大值,然后再把这个矩形内的值全都赋成这个值加上一个数,问最后的最大值是多少

学了二维线段树,以前以为二维线段树只是树套树,后来发现二维线段树必须标记永久化
标记永久化对于线段树上每个节点需要维护两个量,拿维护最大值来举例,你需要维护一个值have,代表这个子树里有这样一个最大值,另外一个值all代表这个子树里全都是这个值
那么赋值的时候我们需要把路径上的have全部更新并更新对应区间的all
查询的时候我们要用路径上所有的all和对应区间的have来更新答案

嗯,然后就没什么了,注意更新的时候一定要取max,不要以为这道题单调就可以直接赋值,这是错的!具体为什么可以自己想一想(其实是我说不明白)

#include
#include
#include
#include
#define N 1010
#define M 3
using namespace std;
int D,S;
struct INSSEG
{
	int all[N*M],hav[N*M];
	void change(int now,int l,int r,int ll,int rr,int v)
	{
		hav[now]=max(hav[now],v);
		if(ll==l&&rr==r)
		{
			all[now]=max(v,all[now]);
			return;
		}
		int mid=(l+r)>>1;
		if(rr<=mid) change(now<<1,l,mid,ll,rr,v);
		else if(ll>mid) change(now<<1|1,mid+1,r,ll,rr,v);
		else change(now<<1,l,mid,ll,mid,v),change(now<<1|1,mid+1,r,mid+1,rr,v);
	}
	int check(int now,int l,int r,int ll,int rr)
	{
		if(ll==l&&rr==r) return hav[now];
		int ret=all[now];
		int mid=(l+r)>>1;
		if(rr<=mid) ret=max(ret,check(now<<1,l,mid,ll,rr));
		else if(ll>mid) ret=max(ret,check(now<<1|1,mid+1,r,ll,rr));
		else ret=max(ret,max(check(now<<1,l,mid,ll,mid),check(now<<1|1,mid+1,r,mid+1,rr)));
		return ret;
	}
};
struct OUSSEG
{
	INSSEG all[N*M],hav[N*M];
	void change(int now,int l,int r,int ll,int rr,int lll,int rrr,int v)
	{
		hav[now].change(1,0,S,lll,rrr,v);
		if(ll<=l&&rr>=r)
		{
			all[now].change(1,0,S,lll,rrr,v);
			return;
		}
		int mid=(l+r)>>1;
		if(rr<=mid) change(now<<1,l,mid,ll,rr,lll,rrr,v);
		else if(ll>mid) change(now<<1|1,mid+1,r,ll,rr,lll,rrr,v);
		else change(now<<1,l,mid,ll,mid,lll,rrr,v),change(now<<1|1,mid+1,r,mid+1,rr,lll,rrr,v);
	}
	int check(int now,int l,int r,int ll,int rr,int lll,int rrr)
	{
		if(ll<=l&&rr>=r) return hav[now].check(1,0,S,lll,rrr);
		int ret=all[now].check(1,0,S,lll,rrr);
		int mid=(l+r)>>1;
		if(rr<=mid) ret=max(ret,check(now<<1,l,mid,ll,rr,lll,rrr));
		else if(ll>mid) ret=max(ret,check(now<<1|1,mid+1,r,ll,rr,lll,rrr));
		else ret=max(ret,max(check(now<<1,l,mid,ll,mid,lll,rrr),check(now<<1|1,mid+1,r,mid+1,rr,lll,rrr)));
		return ret;
	}
}O;
int main()
{
	int n;
	scanf("%d%d%d",&D,&S,&n);
	int d,s,w,x,y;
	while(n--)
	{
		scanf("%d%d%d%d%d",&d,&s,&w,&x,&y);
		int most=O.check(1,0,D,x+1,x+d,y+1,y+s);
		O.change(1,0,D,x+1,x+d,y+1,y+s,most+w);
	}
	printf("%d",O.check(1,0,D,0,D,0,S));
}

你可能感兴趣的:(BZOJ,POI,二维线段树,标记永久化)