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

题意:

一家旅馆有N(1 ≤ N ≤ 50000)间房间,并且所有的房间都是连续排列在同一边,现在每个观光团需要入住房间,要求房间的编号为连续的 r...r+Di1 ,并且r是最小的;
参观者同样可能退房,并且他们每次退房都是编号为 Xi...Xi+Di1 (1XiNDi+1) 的房间。
现在有两种操作:
1. 1 a 每个观光团需要入住a间编号连续的房间
2. 2 a b 观光者需要退房间,其中房间编号是 a...a+b1
要求对于每次询问,输出为观光团分配数目为a的房间中编号最小的房间编号

解析:

利用线段树建立模型,维护最大连续区间长度,其中区间长度就是对应的房间数目,并且对应区间中最左边的断点就是答案,同时因为需要求出连续区间的最大长度,因此每次pushUp时都将左右区间合并,
lsum 维护左区间的最大长度,
rsum 维护右区间的最大长度,
msum 维护区间 1...N 中的最大连续区间长度,
cover 标志对应区间是否为空。

my code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ls o<<1
#define rs o<<1|1
#define lson ls, L, M
#define rson rs, M+1, R
using namespace std;
const int N = 50005;
int cover[N<<2]; //懒惰标记 -1无操作,0区间为空,1区间为满
int lsum[N<<2], rsum[N<<2], msum[N<<2];
int n, m;

void pushDown(int o, int L, int R) {
    if(cover[o] != -1) {
        int M = (L + R)/2;
        cover[ls] = cover[rs] = cover[o];
        lsum[ls] = rsum[ls] = msum[ls] = cover[o] ? 0 : (M - L + 1);
        lsum[rs] = rsum[rs] = msum[rs] = cover[o] ? 0 : (R - M);
        cover[o] = -1;
    }
}

void pushUp(int o, int L, int R) {
    int M = (L + R)/2;
    int len1 = M - L + 1, len2 = R - M;
    lsum[o] = lsum[ls]; rsum[o] = rsum[rs];
    if(lsum[o] == len1) lsum[o] += lsum[rs];
    if(rsum[o] == len2) rsum[o] += rsum[ls];
    msum[o] = max(msum[ls], max(msum[rs],  rsum[ls] + lsum[rs]));
    if(cover[ls] == cover[rs]) cover[o] = cover[ls];
    else cover[o] = -1;
}

void modify(int o, int L, int R, int ql, int qr, int val) {
    if(ql <= L && R <= qr) {
        cover[o] = val;
        lsum[o] = rsum[o] = msum[o] = (val) ? 0 : (R-L+1);
        return ;
    }
    pushDown(o, L, R);
    int M = (L + R)/2;
    if(ql <= M) modify(lson, ql, qr, val);
    if(qr > M) modify(rson, ql, qr, val);
    pushUp(o, L, R);
}

int query(int o, int L, int R, int need) {
    if(L == R) return L;
    pushDown(o, L, R);
    int M = (L + R)/2;
    if(msum[ls] >= need)
        return query(lson, need);
    else if(lsum[rs] + rsum[ls] >= need)
        return M - rsum[ls] + 1;
    else return query(rson, need);
}

void build(int o, int L, int R) {
    cover[o] = -1;
    lsum[o] = rsum[o] = msum[o] = R - L + 1;
    if(L == R) return ;
    int M = (L + R)/2;
    build(lson);
    build(rson);
}

int main() {
    while(scanf("%d%d", &n, &m) != EOF) {
        build(1, 1, n);
        int oper, ql, qr, need;
        while(m--) {
            scanf("%d", &oper);
            if(oper == 1) {
                scanf("%d", &need);
                if(msum[1] < need) {
                    puts("0");
                    continue;
                }
                ql = query(1, 1, n, need);
                printf("%d\n", ql);
                qr = ql + need - 1;
                modify(1, 1, n, ql, qr, 1);
            }else {
                scanf("%d%d", &ql, &need);
                qr = ql + need - 1;
                modify(1, 1, n, ql, qr, 0);
            }
        }
    }
    return 0;
}

你可能感兴趣的:(poj,3667)