BZOJ1513: [POI2006]Tet-Tetris 3D

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

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

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

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#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));
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值