|BZOJ 1593|线段树|Hotel 旅馆

http://www.lydsy.com/JudgeOnline/problem.php?id=1593

luogu免权限地址:https://www.luogu.org/problem/show?pid=2894

线段树记录4个信息:

lm: 左端点开始最长连续空区间 
rm: 右端点开始最长连续空区间
sum:整个区间最长连续空区间

lazy:lazy标记 (-1:没有标记 0:空区间 1:满区间) 

具体请看代码

#include<cstdio>  
#include<algorithm>  
#include<cstring>   
#include<vector> 
#define ms(i,j) memset(i,j, sizeof i);  
using namespace std;
#define lc o*2
#define rc o*2+1
#define M (l+r)/2
const int MAXN = 100000 + 5;
int n,m;
struct st//线段树
{
	int lm[MAXN*4], rm[MAXN*4], lazy[MAXN*4], sum[MAXN*4];
	//lm: 左端点开始最长连续空区间 
	//rm: 右端点开始最长连续空区间
	//sum:整个区间最长连续空区间
	//lazy:lazy标记 (-1:没有标记 0:空区间 1:满区间) 
	void build(int o, int l, int r)
	{
		lm[o] = rm[o] = sum[o] = r-l+1; 
		lazy[o] = -1;
		if (l==r) return ;
		build(lc, l, M);
		build(rc, M+1, r); 
	} //建树 
	void pushup(int o, int len)
	{
		lm[o] = lm[lc];
		if (lm[lc]==len-len/2) lm[o] += lm[rc];
		//如果左孩子全部为可用区间,那么加上右孩子的左端
		rm[o] = rm[rc];
		if (lm[rc]==len/2) rm[o] += rm[lc];
		//如果右孩子全部为可用区间,那么加上左孩子的右端
		sum[o] = max(max(sum[lc], sum[rc]), rm[lc]+lm[rc]);
		//左孩子最大的空区间、有孩子最大的空区间,和跨越左右孩子加在一起的空区间
	}
	void pushdown(int o, int len)
	{
		if(lazy[o]!=-1)
		{
			if (lazy[o]==1)
			{
				sum[lc]=sum[rc]=lm[lc]=rm[lc]=lm[rc]=rm[rc]=0;//全部空 
			} else
			{
				sum[lc]=lm[lc]=rm[lc]=len - len/2;
				sum[rc]=lm[rc]=rm[rc]=len/2;//全部满 
			}
			lazy[lc]=lazy[rc]=lazy[o];
			lazy[o] = -1;//传lazy 
		} 
	}
	void update(int o, int l, int r, int x, int y, int ty)
	{
		if(x<=l&&r<=y)
		{
			lazy[o] = ty;
			if (ty==1) sum[o]=lm[o]=rm[o]=0;
			else sum[o]=lm[o]=rm[o]=r-l+1;
			return ;
		} 
		pushdown(o, r-l+1);
		if (x<=M) update(lc,l,M,x,y,ty);
		if (M<y) update(rc,M+1,r,x,y,ty);
		pushup(o,r-l+1);
	}
	int query(int o, int l, int r, int w)
	{
		if (l==r) return l;
		pushdown(o,r-l+1);
		if (sum[lc]>=w) return query(lc,l,M,w);
		if (rm[lc]+lm[rc]>=w) return M-rm[lc]+1;
		if (sum[rc]>=w) return query(rc,M+1,r,w);
	}
}tree;
int main()  
{  
	scanf("%d%d", &n, &m);
	tree.build(1,1,n);
	for (int i=1;i<=m;i++)
	{
		int type;
		scanf("%d", &type);
		if (type==1)
		{
			int x;
			scanf("%d", &x);
			if (tree.sum[1]<x) printf("0\n");
			else			
			{
				int ans = tree.query(1,1,n,x);
				printf("%d\n", ans);
				tree.update(1,1,n,ans,ans+x-1,1);
			}
		} else
		{
			int x,y;
			scanf("%d%d", &x, &y);
			tree.update(1,1,n,x,x+y-1,0);
		}	
	}
    return 0;  
}  


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值