您的位置:首页 > 其它

POJ 3667 Hotel

2016-07-28 15:06 417 查看
Time Limit: 3000MS Memory Limit: 65536K

Description

The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lake Superior. Bessie, ever the competent travel agent, has named the Bullmoose Hotel on famed Cumberland Street as their vacation residence. This immense hotel has N (1 ≤ N ≤ 50,000) rooms all located on the same side of an extremely long hallway (all the better to see the lake, of course).

The cows and other visitors arrive in groups of size Di (1 ≤ Di ≤ N) and approach the front desk to check in. Each group i requests a set of Di contiguous rooms from Canmuu, the moose staffing the counter. He assigns them some set of consecutive room numbers r..r+Di-1 if they are available or, if no contiguous set of rooms is available, politely suggests alternate lodging. Canmuu always chooses the value of r to be the smallest possible.

Visitors also depart the hotel from groups of contiguous rooms. Checkout i has the parameters Xi and Di which specify the vacating of rooms Xi ..Xi +Di-1 (1 ≤ Xi ≤ N-Di+1). Some (or all) of those rooms might be empty before the checkout.

Your job is to assist Canmuu by processing M (1 ≤ M < 50,000) checkin/checkout requests. The hotel is initially unoccupied.

Input

Line 1: Two space-separated integers: N and M

Lines 2..M+1: Line i+1 contains request expressed as one of two possible formats: (a) Two space separated integers representing a check-in request: 1 and Di (b) Three space-separated integers representing a check-out: 2, Xi, and Di

Output

Lines 1…..: For each check-in request, output a single line with a single integer r, the first room in the contiguous sequence of rooms to be occupied. If the request cannot be satisfied, output 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

【题意】 一个旅馆有N个房间,现有M条指令,指令分两个类型,以1开头的是查询操作,以2开头的是更新操作;

1 X 表示在总区间内查询一个长度为X的空房间,并且要最靠左,能找到的话返回这个区间的左端点并占用了这个区间,找不到返回0;

2 Xi Di , 表示从单位Xi开始,清除一段长度为Di的区间(就是退房),不需要输出。

【解题思路】 此题用线段树做,该题主要是两个操作,更新操作和查询操作;更新操作相对简单一点,用一个标记记录房间是否入住,在通过向下传递标记和返回值来更新每个节点的lsum(左最大连续区间),rsum(右最大连续区间),nsum(最大连续区间);查询要输出区间的具体位置,则有:

1.如果左子区间的nsum不小于X,查询左子区间;

2.若左子区间的rsum加上右子区间的lsum不小于X,直接返回tr[id*2].r-tr[id*2].rsum+1,注意,不需要再递归;

3.若右子区间的nsum不小于X,查询右子区间;

4.若都不符合,则返回0;

【AC代码】

#include<stdio.h>
#include<algorithm>
#define fff 50005
using namespace std;
struct node
{
int l,r,vis;
int lsum,rsum,nsum;
}tr[fff*4];
void pushdown(int id)
{
if(tr[id].vis!=-1)
{
tr[id*2].vis=tr[id*2+1].vis=tr[id].vis;
tr[id*2].lsum=tr[id*2].rsum=tr[id*2].nsum=(tr[id].vis?0:tr[id*2].r-tr[id*2].l+1);
tr[id*2+1].lsum=tr[id*2+1].rsum=tr[id*2+1].nsum=(tr[id].vis?0:tr[id*2+1].r-tr[id*2+1].l+1);
tr[id].vis=-1;
}
}
void pushup(int id)
{
tr[id].lsum=tr[id*2].lsum;
tr[id].rsum=tr[id*2+1].rsum;
tr[id].nsum=max(tr[id*2].rsum+tr[id*2+1].lsum,max(tr[id*2].nsum,tr[id*2+1].nsum));
if(tr[id*2].lsum==tr[id*2].r-tr[id*2].l+1)
tr[id].lsum=tr[id*2].lsum+tr[id*2+1].lsum;
if(tr[id*2+1].rsum==tr[id*2+1].r-tr[id*2+1].l+1)
tr[id].rsum=tr[id*2+1].rsum+tr[id*2].rsum;
}
void build(int id,int l,int r)
{
tr[id].l=l;tr[id].r=r;
tr[id].lsum=tr[id].rsum=tr[id].nsum=r-l+1;
tr[id].vis=-1;  //初始化为-1,入住和退房都可以对线段树进行更新
if(l==r)
return;
int mid=(l+r)/2;
build(id*2,l,mid);
build(id*2+1,mid+1,r);
}
void update(int id,int l,int r,int x)
{
if(tr[id].l==l&&tr[id].r==r)
{
tr[id].vis=x;
tr[id].lsum=tr[id].rsum=tr[id].nsum=(x?0:tr[id].r-tr[id].l+1);
return;
}
pushdown(id);
int mid=(tr[id].l+tr[id].r)/2;
if(r<=mid)
update(id*2,l,r,x);
else if(l>mid)
update(id*2+1,l,r,x);
else
{
update(id*2,l,mid,x);
update(id*2+1,mid+1,r,x);
}
pushup(id);
}
int found(int id,int len)
{
pushdown(id);
//因为要输出最左区间的位置,下面的判断顺序不可以随便调换,必须是从左到右
if(tr[id*2].nsum>=len)
return found(id*2,len);
else if(tr[id*2].rsum+tr[id*2+1].lsum>=len)
return tr[id*2].r-tr[id*2].rsum+1;  //排除了左子区间的情况,可以直接返回该区间的位置
else if(tr[id*2+1].nsum>=len)
return found(id*2+1,len);
else
return 0;
}
int main()
{
int n,m,x,y,z;
while(scanf("%d%d",&n,&m)!=EOF)
{
build(1,1,n);
while(m--)
{
scanf("%d",&x);
if(x==1)
{
scanf("%d",&y);
int k=found(1,y);
printf("%d\n",k);
if(k) //注意,当输出是0的时候,没有人入住,不需要更新
update(1,k,k+y-1,1);
}
else
{
scanf("%d%d",&y,&z);
update(1,y,y+z-1,0);
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: