poj 3667 hotel

本文介绍了一种使用线段树数据结构解决酒店房间预订问题的方法,通过维护连续可用房间的最大长度等信息,实现了高效的房间分配与释放功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Hotel
Time Limit: 3000MS Memory Limit: 65536K
Total Submissions: 15167 Accepted: 6565

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 D(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

Source


题目大意:用N个连续的旅馆房间。m个操作,操作分两种。

先读入x, x==1 表示有一个旅行团要入住,他们需要连续的y个房间,并且要求开始的房间号尽量小,如果无法满足条件就输出0;

x==2 表示从房间y开始有连续z个旅客离开旅馆。

针对每一个操作1,输出最靠前的房间号。

题解:线段树维护区间。

刚看到这道题的时候真是无从下手,都有一头撞死在电脑上的冲动了.后来经过zyf神犇的指点,领悟到了一些门道。

这道题针对每个区间需要维护三个值tr[x]表示当前区间中最长的连续房间数,ls[x]表示从区间的开始最长的连续房间数,rs[x]表示从区间末尾最长的连续房间数。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 60000
using namespace std;
int n,m;
int tr[N*4],ls[N*4],rs[N*4],delta[N*4];
void update(int x)
{
  ls[x]=rs[x]=tr[x]=tr[x<<1]+tr[x<<1|1];//初始化
}
void build(int now,int l,int r)//建树
{
  if (l==r)
   {
   	 tr[now]=1; ls[now]=1; rs[now]=1; return;
   }
  int mid=(l+r)/2;
  build(now<<1,l,mid);
  build(now<<1|1,mid+1,r);
  update(now);
}
void pushdown(int x,int l,int r)//标记下放
{
  if (!delta[x]) return ;
  int mid=(l+r)/2;
  if (!tr[x])
   tr[x<<1]=ls[x<<1]=rs[x<<1]=tr[x];
  else
   tr[x<<1]=ls[x<<1]=rs[x<<1]=mid-l+1;
  if (!tr[x])
   tr[x<<1|1]=ls[x<<1|1]=rs[x<<1|1]=tr[x];
  else
   tr[x<<1|1]=ls[x<<1|1]=rs[x<<1|1]=r-mid;
  delta[x<<1]=delta[x<<1|1]=1;
  delta[x]=0;
}
int find(int now,int l,int r,int len)
{
  if (l==r) return l;
  pushdown(now,l,r);
  int mid=(l+r)/2;
  if (tr[now<<1]>=len)//因为要求房间号尽可能小,所以如果左半部分有满足条件的答案,那么就向左半部分搜寻
   return find(now<<1,l,mid,len);
  else
   if (rs[now<<1]+ls[now<<1|1]>=len)//如果左半部分无法满足,而左半部分的末尾与右半部分的开头可以构成一个合法答案的话,就从左半部分选取尽可能多的房间,即rs[now<<1]
    return mid-rs[now<<1]+1;
   else
    return find(now<<1|1,mid+1,r,len);//最后在从右半部寻找答案
}
void update1(int x,int l,int r)
{
  int mid=(l+r)/2;
  tr[x]=max(max(tr[x<<1],tr[x<<1|1]),rs[x<<1]+ls[x<<1|1]);//最大值有三种可能,全部在左半部分,全部在右半部分,和横跨两部分
  ls[x]=ls[x<<1]+(ls[x<<1]==mid-l+1?ls[x<<1|1]:0);//在更新这里时要格外注意,当前区间的ls[x]不一定等于ls[x<<1]有可能还包含ls[x<<1|1]的一部分
  rs[x]=rs[x<<1|1]+(rs[x<<1|1]==r-mid?rs[x<<1]:0);//rs[x]也是同理
}
void qjchange(int now,int l,int r,int ll,int rr,int k)//与线段上一般的区间修改几乎相同,标记k==0表示占用房间,k==1表示清理出空房间,最后不要忘记更新当前区间的最值
{
 if(l>=ll&&r<=rr)
  {
  	if (k==0)
  	 tr[now]=ls[now]=rs[now]=0;
  	else
  	 tr[now]=ls[now]=rs[now]=r-l+1;
  	delta[now]=1; 
  	return;
  }
 pushdown(now,l,r);
 int mid=(l+r)/2;
 if (ll<=mid)
  qjchange(now<<1,l,mid,ll,rr,k);
 if (rr>mid)
  qjchange(now<<1|1,mid+1,r,ll,rr,k);
 update1(now,l,r);
}
int main()
{
  scanf("%d%d",&n,&m);
  build(1,1,n);
  for (int i=1;i<=m;i++)
  {
   int x,y,z; scanf("%d",&x);
   if (x==1)
    {
      scanf("%d",&y);
      if (tr[1]<y)
       printf("0\n");
      else
      {
       int k=find(1,1,n,y);
       printf("%d\n",k);
       qjchange(1,1,n,k,k+y-1,0);
      }
    }
   else
    {
      scanf("%d%d",&y,&z);
      qjchange(1,1,n,y,y+z-1,1);
    }
  }
}









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值