zoukankan      html  css  js  c++  java
  • POJ 3667 Hotel 线段树 区间合并

    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


    第一次涉及区间合并的题目,多谢玉斌大神的博客。
    区间合并最难处理的就是跨区间问题,所求连续区间有可能跨越两个子树,为了解决跨区间问题,引入两个数组lc[],rc[],lc专门保存该区间从最左端点开始的连续量,rc保存从最右端点开始的连续量。。记住一定是记录从两个端点开始的连续,mc[]就是保存当前的最大连续量,因此判断的时候
    mc[root]=max(mc[Lson],mc[Rson]);首先分别从两个子树中间取得最大量
    mc[root]=max(mc[root],lc[Rson]+rc[Lson]) 为了计算跨区间连续,则比较下lc右子树+rc左子树和当前值,所以知道为什么要从区间端点开始计算起吧。
    玉斌大神用了染色的技巧,使得占用和空出房间都很方便的调用一个函数、、还有懒惰标记,也需要一点点技巧

    很郁闷的是,我自认为把线段树的区间合并应该弄得挺熟练了,结果碰到HDU 3308 和3397,愣是WA的不明不白。。。尤其是3308,这么简单的题目,我WA之后找了网上一个思路跟我一模一样的代码,然后它的居然A掉了,我在作死的找BUG,两份代码几乎一样,我就算参照起来,改自己的代码,差点连变量名都想改成一样的了。。但就是WA。。。我就郁闷死了

    线段树看来得先放一放。。除非我先A掉HDU那两题。。。主要是找BUG。。真的WA的不明不白,我搜了N多博客。思路都是这样。。我左改右改就是通不过。
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define maxn 50006
    #define Lson (x<<1),l,mid
    #define Rson (x<<1|1),mid+1,r
    #define INF 10000005
    using namespace std;
    
    int flag[maxn<<3];
    int lc[maxn<<3];
    int rc[maxn<<3];
    int mc[maxn<<3];
    int max(int a,int b)
    {
        return a>b?a:b;
    }
    
    void build(int x,int l,int r)
    {
        flag[x]=-1;
        lc[x]=rc[x]=mc[x]=r-l+1;
        if (l==r)
        {
         return;
        }
        int mid=(l+r)/2;
        build(Lson);
        build(Rson);
    }
    void pushdown(int x,int l,int r)
    {
        if (flag[x]!=-1)
        {
            int mid=(l+r)/2;
            flag[x<<1]=flag[x<<1|1]=flag[x];
            mc[x<<1]=lc[x<<1]=rc[x<<1]= flag[x]? 0:mid-l+1;
            mc[x<<1|1]=lc[x<<1|1]=rc[x<<1|1]=flag[x]? 0:r-mid;
            flag[x]=-1;
        }
    }
    int search(int a,int x,int l,int r)
    {
        if(l==r)
          return l;
        pushdown(x,l,r);
        int mid=(l+r)/2;
    
        if (mc[x<<1]>=a)
         return search(a,Lson);
        else
         if (rc[x<<1]+lc[x<<1|1]>=a)
        {
    
             return mid-rc[x<<1]+1;
        }
        else
         return search(a,Rson);
    }
    void update(int x,int l,int r)
    {
        int mid=(l+r)/2;
        mc[x]=max(mc[x<<1],mc[x<<1|1]);
        mc[x]=max(mc[x],lc[x<<1|1]+rc[x<<1]);
        lc[x]=lc[x<<1]+ (lc[x<<1]==mid-l+1? lc[x<<1|1]:0);
        rc[x]=rc[x<<1|1]+(rc[x<<1|1]==r-mid? rc[x<<1]:0);
    }
    void color(int L,int R,int c,int x,int l,int r)
    {
        if (L<=l&&r<=R)
        {
            flag[x]=c;
            mc[x]=lc[x]=rc[x]=c?0:r-l+1;
            return;
        }
        pushdown(x,l,r);
        int mid=(l+r)/2;
        if (L<=mid) color(L,R,c,Lson);
        if (R>mid) color(L,R,c,Rson);
        update(x,l,r);
    }
    int main()
    {
        int n,m;
        while (scanf("%d %d",&n,&m)!=EOF)
        {
            build(1,1,n);
            int i,j;
            for (i=1;i<=m;i++)
            {
                int a,b,c;
                scanf("%d",&a);
                if (a==1)
                {
                    scanf("%d",&b);
                    if (mc[1]<b) puts("0");
                    else
                    {
                     int ans=search(b,1,1,n);
                     printf("%d
    ",ans);
                     color(ans,ans+b-1,1,1,1,n);
                    }
                }
                else
                {
                    scanf("%d %d",&b,&c);
                    color(b,b+c-1,0,1,1,n);
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    个性化推荐系统(二)---构建推荐引擎
    个性化推荐系统(一)---今日头条等的内容划分、分类
    双11线上压测netty内存泄露
    数据、信息、知识、智慧
    ReentrantLock的相关方法使用
    公平锁和非公平锁
    Lock中使用Condition实现等待通知
    使用IO流将数据库中数据生成一个文件,结果使用Notepad++打开部分数据结尾出现NUL
    ThreadLocal的使用
    join方法
  • 原文地址:https://www.cnblogs.com/kkrisen/p/3269683.html
Copyright © 2011-2022 走看看