poj 3667

题目大意:有一群奶牛去旅店住宿,询问 是否有连续 size个 房间,如果有就住下,当然,每一次如果有多个符合条件的size,那么我们都要选择左端点最小的那个,如果没有就不住,去别的地方,同时会有其他的操作,即 从 pos开始 size个 房间的客人会 退房

思路:线段树 ,节点记录信息为 lsum记录区间左端空白区,rsum记录右端空白区,msum记录区间最大空白区,cover记录标记情况。

update和query都很简单,重点是要怎样 更新 lsum,rsum,和msum

可以看出,msum = max (左儿子msum,右儿子msum,左儿子rsum+右儿子lsum)。             lsum=左儿子lsum ,如果 左儿子lsum包括了左儿子整个区间,那么就要加上

右儿子 lsum  。             rsum=右儿子rsum,如果 右儿子rsum包括了 右儿子整个区间,那么也要将 左儿子rsum加上去。。

#include<iostream>
#include<algorithm>
using namespace std;

#define lson u<<1
#define rson u<<1|1
#define MAXN 50005
#define max(a,b,c) ((a)>(b)?(a)>(c)?(a):(c):(b)>(c)?(b):(c))

struct Node{
	int lef,rig;
	int lsum,rsum,msum;//lsum记录区间左端空白区,rsum记录右端,msum记录整个区间最大空白区
	int cover;//覆盖标记
}T[MAXN<<2];

void Build(int u,int l,int r){
	T[u].lef=l;
	T[u].rig=r;
	T[u].cover=-1;
	T[u].lsum=T[u].rsum=T[u].msum=r-l+1;
	if(l==r)return;
	int mid=(l+r)>>1;
	Build(lson,l,mid);
	Build(rson,mid+1,r);
}

void PushUp(int u){
	int len=T[u].rig-T[u].lef+1;
	T[u].lsum=T[lson].lsum;
	T[u].rsum=T[rson].rsum;
	if(T[u].lsum==(len+1)>>1)T[u].lsum+=T[rson].lsum;
	if(T[u].rsum==len>>1)T[u].rsum+=T[lson].rsum;
	T[u].msum=max(T[lson].msum,T[rson].msum,T[lson].rsum+T[rson].lsum);
}

void PushDown(int u){
	int len=T[u].rig-T[u].lef+1;
	if(T[u].cover!=-1){
		T[lson].cover=T[rson].cover=T[u].cover;
		T[lson].lsum=T[lson].rsum=T[lson].msum=T[u].cover?0:(len+1)>>1;
		T[rson].lsum=T[rson].rsum=T[rson].msum=T[u].cover?0:len>>1;
		T[u].cover=-1;
	}
}

void Update(int u,int l,int r,int color){
	int len=T[u].rig-T[u].lef+1;
	if(l<=T[u].lef&&T[u].rig<=r){
		T[u].lsum=T[u].rsum=T[u].msum=color?0:len;
		T[u].cover=color;return;
	}
	else {
		PushDown(u);
		if(l<=T[lson].rig)Update(lson,l,r,color);
		if(r>=T[rson].lef)Update(rson,l,r,color);
		PushUp(u);
	}
}

int Query(int u,int size){
	if(T[u].lef==T[u].rig)return T[u].lef;
	else{
		PushDown(u);
		if(T[lson].msum>=size)return Query(lson,size);
		else if(T[lson].rsum+T[rson].lsum>=size)return T[lson].rig-T[lson].rsum+1;
		else return Query(rson,size);
	}
}

int main(){
	int N,M;
	while(~scanf("%d%d",&N,&M)){
		int cmd,pos,size;
		Build(1,1,N);
		while(M--){
			scanf("%d",&cmd);
			if(cmd==1){
				scanf("%d",&size);
				if(T[1].msum<size){puts("0");continue;}
				pos=Query(1,size);
				printf("%d\n",pos);
				Update(1,pos,pos+size-1,1);
			}
			else {
				scanf("%d%d",&pos,&size);
				Update(1,pos,pos+size-1,0);
			}
		}
	}
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值