Hotel(线段树 + 区间合并)

Hotel
Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 11495   Accepted: 4949

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

 

        题意:

        给出 n (0 ~ 50000)和 m(0 ~ 50000),代表有 N 个房间, M 个入住情况,后给出 M 个入住情况,1 代表要入住,2 代表有退房,1 后跟着一个数 num,代表要入住连续 num 间,2 后跟着两个数 ans,num,代表有 ans 这间房间开始,连续退掉 num 间房间。每个 1 操作对应输出一个数,每次入住都要找到最靠左的连续区间,且输出第一个序号,如果不满足则输出 0。

 

        思路:

        线段树 + 区间合并。用 0 代表房间为空,1 代表房间为满,同时开数组 lmax(代表区间的左边界开始的最大的连续房间数),rmax(代表区间的右边界开始的最大连续的房间数),mmax(代表整个区间的最大连续块)。看 push_up 的代码:

void push_up(int node, int l, int r) {
        int mid = (r + l) >> 1;

        lmax[node] = lmax[node << 1];  //左边界最大等于左儿子的左边界最大
        rmax[node] = rmax[node << 1 | 1];  //右边界最大等于右儿子的右边界最大
        if (lmax[node] == mid - l + 1) 
            lmax[node] += lmax[node << 1 | 1];   
            //若刚好等于左儿子整个区间,则还需加上右儿子的左最大
        if (rmax[node] == r - mid) 
            rmax[node] += rmax[node << 1];
            //若刚好等于右儿子整个区间,则还需加上左儿子的右最大

        mmax[node] = max(rmax[node << 1] + lmax[node << 1 | 1],
                         max(mmax[node << 1], mmax[node << 1 | 1]));
            //最大值,要不是左儿子最大,要不是右儿子最大,要不是中间部分最大
}

 

 

         再看询问操作:
         首先访问左区间,再来访问中间段,最后访问右区间。

int query (int node, int l, int r, int num) {
        if (l == r) return l;

        push_down(node, l, r);
        int mid = (r + l) >> 1;
        if (mmax[node << 1] >= num)  //比较的是左儿子的最大值
            return query(node << 1, l, mid, num);
        else if (rmax[node << 1] + lmax[node << 1 | 1] >= num) 
            return mid - rmax[node << 1] + 1;
        return query(node << 1 | 1, mid + 1, r, num);
}

 

         AC:

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

const int MAX = 50005;

int hotel[MAX * 10];
int mmax[MAX * 10], lmax[MAX * 10], rmax[MAX * 10];

void push_down(int node, int l, int r) {
        if (hotel[node] != -1) {
                hotel[node << 1] = hotel[node << 1 | 1] = hotel[node];

                int mid = (r + l) >> 1;
                mmax[node << 1] = rmax[node << 1] = lmax[node << 1] =
                                    (hotel[node] ? 0 : mid - l + 1);

                mmax[node << 1 | 1] = lmax[node << 1 | 1] = rmax[node << 1 | 1] =
                                    (hotel[node] ? 0 : r - mid);

                hotel[node] = -1;
        }
}

void push_up(int node, int l, int r) {
        int mid = (r + l) >> 1;

        lmax[node] = lmax[node << 1];
        rmax[node] = rmax[node << 1 | 1];
        if (lmax[node] == mid - l + 1) 
            lmax[node] += lmax[node << 1 | 1];
        if (rmax[node] == r - mid) 
            rmax[node] += rmax[node << 1];

        mmax[node] = max(rmax[node << 1] + lmax[node << 1 | 1],
                         max(mmax[node << 1], mmax[node << 1 | 1]));
}

void build (int node, int l, int r) {
        if (l == r) {
                hotel[node] = -1;
                mmax[node] = lmax[node] = rmax[node] = r - l + 1;
        } else {
                int mid = (r + l) >> 1;
                build (node << 1, l, mid);
                build (node << 1 | 1, mid + 1, r);
                hotel[node] = -1;
                push_up(node, l, r);
        }
}

void update (int node, int l, int r, int il, int ir, int s) {
        if (il > r || ir < l) return;
        if (il <= l && ir >= r) {
                hotel[node] = s;
                mmax[node] = lmax[node] = rmax[node] =
                                    (s ? 0 : r - l + 1);
                return;
        }

        push_down(node, l, r);
        int mid = (r + l) >> 1;
        update(node << 1, l, mid, il, ir, s);
        update(node << 1 | 1, mid + 1, r, il, ir, s);
        push_up(node, l, r);
}

int query (int node, int l, int r, int num) {
        if (l == r) return l;

        push_down(node, l, r);
        int mid = (r + l) >> 1;
        if (mmax[node << 1] >= num) 
            return query(node << 1, l, mid, num);
        else if (rmax[node << 1] + lmax[node << 1 | 1] >= num) 
            return mid - rmax[node << 1] + 1;
        return query(node << 1 | 1, mid + 1, r, num);
}

int main() {
        int n, m;
        scanf("%d%d", &n, &m);

        build (1, 1, n);

        while (m--) {

                int way;
                scanf("%d", &way);

                if (way == 1) {
                        int num;
                        scanf("%d", &num);

                        if (mmax[1] < num) {
                                puts("0");
                                continue;
                        }

                        int in = query(1, 1, n, num);
                        printf("%d\n", in);
                        update(1, 1, n, in, in + num - 1, 1);
                } else {
                        int f, num;
                        scanf("%d%d", &f, &num);
                        update(1, 1, n, f, f + num - 1, 0);
                }

        }

        return 0;
}
 

 

 

         

 

你可能感兴趣的:(线段树)