POJ 3667 Hotel

题意:n个房间,可以进行

                 操作1(插入连续的x个人,并输出这批人占据的第一个房间号,如果放不下,输出0);

                 操作2(从第x个房间开始,连续清空y个房间)。

思路:区间更新

AC代码:

#include<iostream>
#include<cstdio>
using namespace std;
struct node
{
	int l,r,cover;//cover记录是否有人 -1,0,1 
	int s,e,n;// 表示左端点起最大长度,右端点起最大长度,整个区间最大长度 
}hotel[200000]; 
void Push_Up(int l,int r,int rt)    //  想父节点更新;
{
    hotel[rt].s=hotel[rt<<1].s;
    hotel[rt].e=hotel[rt<<1|1].e;
    int mid=(l+r)>>1;
    if(hotel[rt].s==mid-l+1) hotel[rt].s+=hotel[rt<<1|1].s;
    if(hotel[rt].e==r-mid) hotel[rt].e+=hotel[rt<<1].e;
    hotel[rt].n=max(max(hotel[rt<<1].n,hotel[rt<<1|1].n),hotel[rt<<1].e+hotel[rt<<1|1].s);
}
void down(int k)
{
	if(hotel[k].cover!=-1)//不等于-1表示需要向下更新 
	{
		hotel[k*2].cover=hotel[k*2+1].cover=hotel[k].cover;
		if(hotel[k].cover) //如果等于1,说明将区间标记为0,即表示住人;
		{
			hotel[k*2].s=hotel[k*2].e=hotel[k*2].n=0;
			hotel[k*2+1].s=hotel[1+k*2].e=hotel[1+k*2].n=0;
		}
		else//如果为0 
		{
			hotel[k*2].s=hotel[k*2].e=hotel[k*2].n=hotel[k*2].r-hotel[k*2].l+1;
			hotel[k*2+1].s=hotel[1+k*2].e=hotel[1+k*2].n=hotel[k*2+1].r-hotel[k*2+1].l+1;
		}
		hotel[k].cover=-1;//已更新,清零 
	} 
} 
void build(int s,int e,int k)
{
	hotel[k].l=s;
	hotel[k].r=e;
	hotel[k].cover=-1;//将所有cover记为无人 
	hotel[k].s=hotel[k].e=hotel[k].n=e-s+1;//定义区间的左起、右起 、整个区间长度 
	if(s==e) return;
	int m=(s+e)/2;
	build(s,m,k*2);
	build(m+1,e,k*2+1); 
}
int query(int s,int e,int v,int k)
{
	if(s==e)  return s;
	int m=(s+e)/2;
	down(k);
	if(hotel[k*2].n>=v) return query(s,m,v,k*2);//如果左枝的房间足够,查询左枝即可 
	else if(hotel[k*2].e+hotel[k*2+1].s>=v) return m-hotel[k*2].e+1;//或者左枝的右起加右枝的左起足够,返回左枝的点 
	else return query(m+1,e,v,k*2+1);//否则查询右枝 
}
void update(int s,int e,int num,int k)
{
	int l=hotel[k].l;
	int r=hotel[k].r;
	if(l==s&&r==e)
	{
		hotel[k].cover=num;
		if(num)	hotel[k].s=hotel[k].e=hotel[k].n=0;
		else	hotel[k].s=hotel[k].e=hotel[k].n=e-s+1;
		return;
	}
	down(k);
	int m=(l+r)/2;
	if(e<=m) update(s,e,num,k<<1);
    else if(s>m) update(s,e,num,k<<1|1);
    else{
        update(s,m,num,k<<1);
        update(m+1,e,num,k<<1|1);
    }
	Push_Up(hotel[k].l,hotel[k].r,k);
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);//输入总房间数和样例个数 
	build(1,n,1);//建立房间 
	while(m--)
	{
		int k,a,b;
		scanf("%d%d",&k,&a);
		if(k==1)
		{
			if(hotel[1].n<a) printf("0\n");//如果总的剩余房间数小于a 
			else 
			{
				b=query(1,n,a,1);//找到第一个没住人的房间号 
				printf("%d\n",b);
				update(b,b+a-1,1,1);//把人安排进去(置一) 
			}
		}
		else 
		{
			scanf("%d",&b);
			update(a,a+b-1,0,1);//把人请出去(置〇) 
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值