POJ-3667-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 ≤ 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


题意:n个连续的房间m个操作。操作分两种,第一种以1 a形式给出,找到能连续容下a个人的连续房间,并输出左端点的编号,如果找不到就输出0.第二种以2 a b的形式给出,表示以a为起点的b个房间都清空。

思路:lsum存的是从本节点区间最左端开始(向右)一共有lsum个连续的空房间,rlsum 存的是从本节点区间最右端开始(向左)一共有lsum个连续的空房间,msum存的是本区间一共最多有msum个连续的空房间,cover 的值有三种 -1,0,1,懒惰标记,-1代表不需要操作,0代表要将此区间置空,1代表要将此区间置满。如何判断能否住下a个连续房间呢,其实当msum[1](连续空房间的总和)>= a时就能住下。

详细解释请看代码注释。

#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
 #define mid (l+r)>>1
#define abbreviations int l,int r,int rt
const int maxn = 55555;
int lsum[maxn<<2] , rsum[maxn<<2] , msum[maxn<<2];
int cover[maxn<<2];
/*
更新该节点的儿子接节点。
若该节点的cover值为-1就不需要执行,若为0,将左儿子的区间,右儿子的区间置空,若为1,则置满。
分别对应改变对应lsum rsum  msum  cover 值,改变儿子的之后注意要将该节点的cover值变为 -1。
 */
void PushDown(abbreviations, int m) 
{
    if (cover[rt] != -1)
    {
        cover[rt<<1] = cover[rt<<1|1] = cover[rt];
        //cover[rt]为1(真)则把lsum rsum  msum  cover赋为0,代表房间满了,为0(假)时则赋为m-l+1,代表有m-l+1个房间
        msum[rt<<1] = lsum[rt<<1] = rsum[rt<<1] = cover[rt] ? 0 : m - l + 1;
        //cover[rt]为1(真)则把lsum rsum  msum  cover赋为0,代表房间满了,反之为0(假)时则赋为r-m,代表有r-m个房间 
        msum[rt<<1|1] = lsum[rt<<1|1] = rsum[rt<<1|1] = cover[rt] ? 0 : r - m;
        cover[rt] = -1;
    }
}

void PushUp(abbreviations, int m) //回溯更新该节点的父节点的  lsum   rsum  msum的值。
{
    lsum[rt] = lsum[rt<<1]; 
    rsum[rt] = rsum[rt<<1|1];
    if (lsum[rt] == m - l + 1) lsum[rt] += lsum[rt<<1|1];////表示lsum左儿子的值没变,所以要加上lsum右儿子的值
    if (rsum[rt] == r - m ) rsum[rt] += rsum[rt<<1]; //表示rsum右儿子的值没变,所以要加上rsum左儿子的值
    msum[rt] = max(lsum[rt<<1|1] + rsum[rt<<1] , max(msum[rt<<1], msum[rt<<1|1])); //msum值等于  max(右儿子的lsum值 + 左儿子的rsum值, 左儿子的msum值,右儿子的msum值)
}
void build(abbreviations)
{
    msum[rt] = lsum[rt] = rsum[rt] = r - l + 1;
    cover[rt] = -1;
    if (l == r) return ;
    int m = mid;
    build(lson);
    build(rson);
}
void update(int L,int R,int c, abbreviations)
{
    if (L <= l && r <= R)
    {
        //cover[rt]为1(真)则把lsum rsum  msum  cover赋为0,代表房间满了,反之为假时则赋为r-l+1,代表有r-l+1个房间
        msum[rt] = lsum[rt] = rsum[rt] = c ? 0 : r - l + 1;
        cover[rt] = c;
        return ;
    }
    int m = mid;
    PushDown(l, r, rt, m);
    if (L <= m) update(L , R , c , lson);   
    if (m < R) update(L , R , c , rson);
    PushUp(l, r, rt, m);
}
int query(int w, abbreviations)
{
    if (l == r) return l;
    int m = mid;
    PushDown(l, r, rt, m);
    if (msum[rt<<1] >= w) return query(w , lson);
    if (rsum[rt<<1] + lsum[rt<<1|1] >= w) return m - rsum[rt<<1] + 1; //满足则返回房间号
    return query(w, rson);
}
int main()
{
    int n , m;
    scanf("%d%d",&n,&m);
    build(1 , n , 1);
    while (m --)
    {
        int op , a , b;
        scanf("%d",&op);
        if(op == 1)
        {
            scanf("%d",&a);
            if (msum[1] < a) puts("0");
            else
            {
                int p = query(a , 1 , n , 1);
                printf("%d\n",p);
                update(p , p + a - 1 , 1 , 1 , n , 1); //住进人之后要更新
            }
        }
        else
        {
            scanf("%d%d",&a,&b);
            update(a , a + b - 1 , 0 , 1 , n , 1);
        }
    }
    return 0;
}



猜你喜欢

转载自blog.csdn.net/sugarbliss/article/details/80554481
今日推荐