BZOJ1593: [Usaco2008 Feb]Hotel 旅馆 线段树

1593: [Usaco2008 Feb]Hotel 旅馆

Time Limit: 10 Sec   Memory Limit: 64 MB

Description

奶牛们最近的旅游计划,是到苏必利尔湖畔,享受那里的湖光山色,以及明媚的阳光。作为整个旅游的策划者和负责人,贝茜选择在湖边的一家著名的旅馆住宿。这个巨大的旅馆一共有N (1 <= N <= 50,000)间客房,它们在同一层楼中顺次一字排开,在任何一个房间里,只需要拉开窗帘,就能见到波光粼粼的湖面。 贝茜一行,以及其他慕名而来的旅游者,都是一批批地来到旅馆的服务台,希望能订到D_i (1 <= D_i <= N)间连续的房间。服务台的接待工作也很简单:如果存在r满足编号为r..r+D_i-1的房间均空着,他就将这一批顾客安排到这些房间入住;如果没有满足条件的r,他会道歉说没有足够的空房间,请顾客们另找一家宾馆。如果有多个满足条件的r,服务员会选择其中最小的一个。 旅馆中的退房服务也是批量进行的。每一个退房请求由2个数字X_i、D_i 描述,表示编号为X_i..X_i+D_i-1 (1 <= X_i <= N-D_i+1)房间中的客人全部离开。退房前,请求退掉的房间中的一些,甚至是所有,可能本来就无人入住。 而你的工作,就是写一个程序,帮服务员为旅客安排房间。你的程序一共需要处理M (1 <= M < 50,000)个按输入次序到来的住店或退房的请求。第一个请求到来前,旅店中所有房间都是空闲的。

Input

* 第1行: 2个用空格隔开的整数:N、M

* 第2..M+1行: 第i+1描述了第i个请求,如果它是一个订房请求,则用2个数字 1、D_i描述,数字间用空格隔开;如果它是一个退房请求,用3 个以空格隔开的数字2、X_i、D_i描述

Output

* 第1..??行: 对于每个订房请求,输出1个独占1行的数字:如果请求能被满足 ,输出满足条件的最小的r;如果请求无法被满足,输出0

Sample Input

10 6
1 3
1 3
1 3
1 3
2 5 5
1 6

Sample Output

1
4
7
0
5

HINT

 

Source

题解:
维护一颗线段树,每个节点包含的特殊信息有:
1.左端点开始最大连续空着的房间数;
2.右端点开始最大连续空着的房间数;
3.区间中最大连续空着的房间数;
pushup注意:
把x最大连续空房间数设成max(x<<1最大连续空房间数,x<<1|1最大连续空房间数,x<<1右端点最大连续空房间数+x<<1|1左端点最大连续空房间数);
注意如果x<<1或x<<1|1区间全为空,x的右端点最大连续空房间数&左端点最大连续空房间数需要特殊处理
找最小包含x个空房间的区间:
对于每一个节点如果x<<1仍然包含一个有连续x个空房间,向左儿子递归
左区间没有符合条件的区间时,看左右儿子交界处可不可以有连续x个空房间。如果有,直接返回这个左右儿子交界区间的最左端坐标就可以了。
其次返回右儿子区间继续找
如果找到了一个完整的区间也可以直接返回区间左端点坐标

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=50005;
struct Tree
{int l,r,mx,ml,mr,lazy,sum;}T[N*4];
int n,m;
void pushup(int x)
{
	int lc=x<<1,rc=x<<1|1;
	T[x].mx=max(max(T[lc].mx,T[rc].mx),T[lc].mr+T[rc].ml);
	T[x].ml=T[lc].ml;
	if(T[lc].ml==T[lc].sum) T[x].ml=T[lc].sum+T[rc].ml; 
	T[x].mr=T[rc].mr;
	if(T[rc].mr==T[rc].sum) T[x].mr=T[rc].sum+T[lc].mr; 
}
void build(int x,int l,int r)
{
	T[x].l=l,T[x].r=r;
	T[x].sum=T[x].r-T[x].l+1;
	if(l==r)
	{
		T[x].mx=1;
		T[x].ml=1;
		T[x].mr=1;
	    return;
	}
	int mid=(l+r)>>1;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
	pushup(x);
}
void pushdown(int x)
{
	int lc=x<<1,rc=x<<1|1;
	if(T[x].lazy==-1)
	{
	    T[lc].ml=T[lc].mr=T[lc].mx=T[lc].sum;
	    T[rc].ml=T[rc].mr=T[rc].mx=T[rc].sum;
	}
	else
	{
		T[lc].ml=T[lc].mr=T[lc].mx=0;
	    T[rc].ml=T[rc].mr=T[rc].mx=0;
	}
	T[lc].lazy=T[x].lazy;
	T[rc].lazy=T[x].lazy;
	T[x].lazy=0;
}
int Query(int x,int len)
{
	if(len==T[x].sum) return T[x].l;
	if(T[x].lazy) pushdown(x);
	int mid=(T[x].l+T[x].r)>>1;
	if(T[x<<1].mx>=len) return Query(x<<1,len);
    else if(T[x<<1].mr+T[x<<1|1].ml>=len) return mid-T[x<<1].mr+1;
    else return Query(x<<1|1,len);
}
void Modify(int x,int l,int r,int v)
{
	if(T[x].l==l&&T[x].r==r)
	{
		if(v==-1) T[x].ml=T[x].mr=T[x].mx=T[x].sum;
		else T[x].ml=T[x].mr=T[x].mx=0;
		T[x].lazy=v;
		return;
	}
	if(T[x].lazy) pushdown(x);
	int mid=(T[x].l+T[x].r)>>1;
	if(r<=mid) Modify(x<<1,l,r,v);
	else if(l>mid) Modify(x<<1|1,l,r,v);
	else Modify(x<<1,l,mid,v),Modify(x<<1|1,mid+1,r,v);
	pushup(x);
}
int main()
{
	scanf("%d%d",&n,&m);
	build(1,1,n);
	for(int i=1;i<=m;i++)
	{
		int o,x,y;
		scanf("%d%d",&o,&x);
		if(o==1)
		{
			if(T[1].mx<x) printf("0\n");
			else
			{
				int f=Query(1,x);
				printf("%d\n",f);
				Modify(1,f,f+x-1,1);
			}
		}
		else
		{
			scanf("%d",&y);
			Modify(1,x,x+y-1,-1);
		}
	}
}






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值