• PKU 3667 Hotel(线段树)


                                                                                    Hotel            

    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 ≤ XiN-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
    
    题意:有一个旅店,刚开始有一段连续的房间,有两种操作,1、预定房间,找最靠前的一段连续D个房间(如果存在的话);2、退订房间,将[x,x+D-1]区间的房间退订。

    解析:线段树维护,每个节点维护以下几个信息:左、右端点(le,ri),区间长度(len),从左边开始的最大连续长度(lelen),从右边开始的最大长度(rilen),该区间内最大连续长度(maxlen)。是否被预定用1和0表示。每次pushup(更新)时,更新
    lelen,rilen,maxlen.首先lelen=lson.lelen(左儿子的),如果lelen==lson.len,说明可以向右扩展,那么lelen+=rson.lelen;rilen同理更新,maxlen=max{lson.maxlen,rson.maxlen,lelen,rilen,lson.rilen+rson.lelen};
    有了这些信息,就很好去查找答案。

    代码如下:
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<queue>
    #include<vector>
    #include<iterator>
    #include<utility>
    #include<sstream>
    #include<iostream>
    #include<cmath>
    #include<stack>
    using namespace std;
    const int INF=1000000007;
    const double eps=0.00000001;
    const int maxn=50005;
    int N,M;
    struct node
    {
        int le,ri,len;
        int maxlen,lelen,rilen; //区间最大长度,左边最大长度,右边最大长度
        void init(int state)    //根据是否被标记更新
        {
            maxlen=state*len;
            lelen=rilen=maxlen;
        }
    }tree[4*maxn];
    void build_tree(int le,int ri,int id)  //初始化
    {
        tree[id].le=le,tree[id].ri=ri;
        tree[id].len=ri-le+1;
        tree[id].init(1);
        if(le==ri)  return;
        int mid=(le+ri)/2;
        build_tree(le,mid,id*2);
        build_tree(mid+1,ri,id*2+1);
        return;
    }
    void pushdown(int id)
    {
        node& t=tree[id];
        if(t.maxlen==t.len||t.maxlen==0)  //全被预定或是全未预定 
        {
            int state=(t.maxlen==t.len);
            tree[id*2].init(state);
            tree[id*2+1].init(state);
        }
    }
    void pushup(int id)
    {
        node& fa=tree[id];           //父亲
        node& lson=tree[id*2];       //左儿子
        node& rson=tree[id*2+1];     //右儿子
        fa.lelen=lson.lelen;
        if(fa.lelen==lson.len)  fa.lelen+=rson.lelen;  //可扩展
        fa.rilen=rson.rilen;
        if(fa.rilen==rson.len)  fa.rilen+=lson.rilen;
        fa.maxlen=max(lson.maxlen,rson.maxlen);       //更新maxlen
        fa.maxlen=max(fa.maxlen,max(fa.lelen,fa.rilen));
        fa.maxlen=max(fa.maxlen,lson.rilen+rson.lelen);
    }
    int query(int id,int need)
    {
        if(tree[id].maxlen<need)  return 0;  //无解
        if(tree[id].lelen>=need)  return tree[id].le;   //最左边可行
        if(tree[id*2].maxlen>=need)  return query(id*2,need);   //往左边找
        if(tree[id*2].rilen+tree[id*2+1].lelen>=need)  return tree[id*2].ri-tree[id*2].rilen+1;  //中间
        return query(id*2+1,need);    //右边
    }
    void update(int x,int y,int id,int state)
    {
        int le=tree[id].le,ri=tree[id].ri;
        if(x<=le&&ri<=y){  tree[id].init(state); return; }
        pushdown(id);
        int mid=(le+ri)/2;
        if(x<=mid)  update(x,y,id*2,state);
        if(y>mid)  update(x,y,id*2+1,state);
        pushup(id);
    }
    void solve1()
    {
        int start;
        scanf("%d",&start);
        int ans=query(1,start);
        printf("%d
    ",ans);
        if(ans)  update(ans,ans+start-1,1,0);   //找到才更新
    }
    void solve2()
    {
        int start,skip;
        scanf("%d%d",&start,&skip);
        update(start,start+skip-1,1,1);
    }
    int main()
    {
        cin>>N>>M;
        build_tree(1,N,1);
        for(int i=1;i<=M;i++)
        {
            int type;
            scanf("%d",&type);
            if(type==1)  solve1();
            else  solve2();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Codeforces Round #564 (Div. 1)
    Codeforces Round #569 (Div. 1)
    SDOI2019R2游记
    BZOJ 3555: [Ctsc2014]企鹅QQ
    SDOI2019R1游记
    计数的一些东西
    多项式的各种操作
    BZOJ 5424: 烧桥计划
    Codeforces Round #545 (Div. 1)
    概率期望学习笔记
  • 原文地址:https://www.cnblogs.com/wust-ouyangli/p/4755780.html
Copyright © 2020-2023  润新知