POJ 1823 Hotel(线段树)

  • 题目大意:
    旅店有N个房间,排成一排,房间编号为1~N。有三种类型的操作:
    第1种,输入i和M。表示i ~ i + M - 1这段房间入住旅客。
    第2中,输入i和M。表示i ~ i + M - 1这段房间离开旅客。
    第3中,需要输出最多的连续的空房间。
    有P次操作。3 <= N <= 16000,3 <= P <= 200000。

  • 解题思路:
    典型的线段树。关键是怎样去维护最大的连续的。设一个节点最大的连续的空房间为max_len,从左边起连续的空房间为l_c,从右边起连续的空房间为r_c。那么合并两个区间的时候,就要考虑合并之后可能会形成一段新的连续的空房间。还有就是在更新l_c和r_c的时候也是需要注意的。代码一看就懂,有什么写得不好的地方请多指教!

  • Show me the code!

#include <cstdio>
#define mid l + (r - l) / 2
#define lson id << 1, l, mid
#define rson id << 1 | 1, mid + 1, r
using namespace std;
const int MAXN = 16001;
class Node{
    public:
        int max_len, l_c, r_c;
        Node(){

        }
        Node(int max_len, int l_c, int r_c) {
            this->max_len = max_len;
            this->l_c = l_c;
            this->r_c = r_c;
        }
}tree[MAXN * 4];
int laze[MAXN * 4];
int max(int a, int b, int c) {
    a = a > b ? a : b;
    a = a > c ? a : c;
    return a;
}
Node max(int id1, int l1, int r1, int id2, int l2, int r2) {
    Node res;
    res.max_len = max(tree[id1].max_len, tree[id2].max_len, tree[id1].r_c + tree[id2].l_c);
    if (tree[id1].l_c == r1 - l1 + 1) res.l_c = tree[id1].l_c + tree[id2].l_c;
    else res.l_c = tree[id1].l_c;
    if (tree[id2].r_c == r2 - l2 + 1) res.r_c = tree[id2].r_c + tree[id1].r_c;
    else res.r_c = tree[id2].r_c;
    return res;
}
void build(int id, int l, int r) {
    laze[id] = -1;
    if (l == r) tree[id] = Node(1, 1, 1);
    else {
        build(lson);
        build(rson);
        tree[id] = max(lson, rson);
    }
}
void pushdown(int id, int l, int r) {
    if (laze[id] == 1) {
        tree[id << 1] = Node(0, 0, 0);
        laze[id << 1] = 1;
        tree[id << 1 | 1] = Node(0, 0, 0);
        laze[id << 1 | 1] = 1;
    }
    else {
        int t_l = l, t_r = mid;
        int d = t_r - t_l + 1;
        tree[id << 1] = Node(d, d, d);
        laze[id << 1] = 0;
        t_l = mid + 1, t_r = r;
        d = t_r - t_l + 1;
        tree[id << 1 | 1] = Node(d, d, d);
        laze[id << 1 | 1] = 0;
    }
    laze[id] = -1;
}
void updata(int id, int l, int r, int L, int R, int flag) {
    if (R < l || r < L) return;
    if (L <= l && r <= R) {
        if (flag == 1) {
            tree[id] = Node(0, 0, 0);
            laze[id] = 1;
        }
        else {
            tree[id] = Node(r - l + 1, r - l + 1, r - l + 1);
            laze[id] = 0;
        }
        return;
    }
    if (laze[id] != -1) pushdown(id, l, r);
    updata(lson, L, R, flag);
    updata(rson, L, R, flag);
    tree[id] = max(lson, rson);
}
int main() {
    int N, P;
    scanf("%d%d", &N, &P);
    build(1, 1, N);
    for (int a = 0; a < P; ++a) {
        int op;
        scanf("%d", &op);
        if (op == 3) {
            printf("%d\n", tree[1].max_len);
        }
        else {
            int a, b;
            scanf("%d%d", &a, &b);
            if (op == 1) updata(1, 1, N, a, a + b - 1, 1);
            else updata(1, 1, N, a, a + b - 1, 0);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值