Hotel POJ - 3667 (区间合并 + 区间查询)

Posted shallow-dream

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hotel POJ - 3667 (区间合并 + 区间查询)相关的知识,希望对你有一定的参考价值。

Hotel  POJ - 3667 

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

 

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <list>
#include <deque>
#include <queue>
#include <stack>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <iomanip>
#define ull unsigned long long
#define ll long long
#define pb push_back
#define mem(sum,x) memset(sum,x,sizeof(sum))
#define rep(i,start,end) for(int i=start;i<=end;i++)
#define per(i,end,start) for(int i=end;i>=start;i--)
#define tle ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
using namespace std;
const int mod = 998244353;
const int mxn = 2e5 +7;
int _,n,m,t,k,u,v,ans,cnt,ok,lim,op;
ll w[mxn] , cost[mxn] ,  far[mxn] , siz[mxn];
char ch;
#define lc now<<1
#define rc now<<1|1
string str ;
struct node {ll l,r,val,lazy,mx,mn;}p[mxn<<4];
int lmx[mxn] , rmx[mxn] , num[mxn] ,lazy[mxn] ;/// 区间左端点起最长连续区间,区间右端点起最长连续区间,整个节点区间最长连续区间,lazy标记
void pushup(int l,int r,int now)
{
    lmx[now] = lmx[lc] ; rmx[now] = rmx[rc];   /// 继承区间左端点起的最长连续区间,区间右端点起的最长连续区间
    int mid = (l+r)>>1;
    if(lmx[now]==mid-l+1) lmx[now]+=lmx[rc];   /// 区间左端点继承的最长连续区间等于区间长度,那么就加上右孩子的左端点起的最长连续区间
    if(rmx[now]==r-mid)   rmx[now]+=rmx[lc];   /// 区间右端点继承的最长连续区间等于区间长度,那么就加上左孩子的右端点起的最长连续区间
    num[now] = max( rmx[lc]+lmx[rc] , max(num[lc],num[rc]) );  /// 更新整个区间的最长连续区间值
}
void pushdown(int l,int r,int now)
{
    if(lazy[now]>=0){  /// 标记为1 0 ,那么只要判断大于0即可
        int mid = (l+r)>>1;
        lazy[lc] = lazy[rc] = lazy[now] ;
        lmx[lc] = rmx[lc] = num[lc] = lazy[now]?0:(mid-l+1);
        lmx[rc] = rmx[rc] = num[rc] = lazy[now]?0:r-mid;
        lazy[now] = -1 ;
    }
}
void build(int l,int r,int now)
{
    if(l==r){
        lmx[now] = rmx[now] = num[now] = 1 ; return ;  /// 初始化叶子节点的最长区间为1
    }
    int mid = (l+r)>>1;
    build(l,mid,lc);build(mid+1,r,rc);pushup(l,r,now); /// 向上更新最长区间值
}
void up(int l,int r,int L,int R,int now,int lim)  /// 整个区间的左右端点,更新区间的左右端点,树的节点,退房标记还是入住标记
{
    if(L<=l && R>=r){
        num[now] = lmx[now] = rmx[now] = lim?0:(r-l+1);
        lazy[now] = lim ; /// 更新区间标记
        return ;
    }
    pushdown(l,r,now);
    int mid = (l+r)>>1;
    if(L<=mid) up(l,mid,L,R,lc,lim);
    if(R>mid)  up(mid+1,r,L,R,rc,lim);
    pushup(l,r,now);
}
int ask(int l,int r,int k,int now)
{
    if(l==r) return l; /// 区间端点相同即叶子节点,直接返回区间端点
    pushdown(l,r,now); /// 向下传递lazy值
    int mid = (l+r)>>1 ;
    if(num[lc]>=k) return ask(l,mid,k,lc); /// 左区间最左连续区间满足需求的K个房间,则计算左区间
    if(rmx[lc]+lmx[rc]>=k) return mid-rmx[lc]+1; /// 左区间的最右连续区间和右区间的最左连续区间满足K个需求,则 均值 - 右区间的最左连续区间 + 1 即为左区间最右连续区间的起始值
    return ask(mid+1,r,k,rc); /// 在右区间查找
}
int main()
{
    while(cin>>n>>m)
    {
        build(1,n,1);
        while(m--)
        {
            cin>>op;
            if(op==1){
                cin>>k;
                if(num[1]<k){ /// 特判整个区间是否满足K个房间的需求
                    cout<<0<<endl;continue;
                }
                ans = ask(1,n,k,1);
                cout<<ans<<endl;
                up(1,n,ans,ans+k-1,1,1); /// 将找到的连续K个房间标记为使用
            }else{
                cin>>k>>cnt;
                up(1,n,k,k+cnt-1,1,0);
            }
        }
    }
}

 

以上是关于Hotel POJ - 3667 (区间合并 + 区间查询)的主要内容,如果未能解决你的问题,请参考以下文章

poj3667-Hotel-线段树-区间合并

poj 3667 Hotel (线段树+区间合并)

POJ 3667 Hotel(线段树+区间合并)

线段树区间合并POJ3667-Hotel

POJ 3667 Hotel 线段树 区间合并 + Lazy-tag

POJ 3667 Hotel(线段树区间合并)