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

本文介绍了一种利用线段树实现的高效算法,用于解决酒店房间分配问题,包括判断是否有连续长度为a的空房间以及如何将指定范围内的房间清空。详细解释了线段树的数据结构及其在该场景下的应用,提供了代码实现和相关链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

题目传送门

/*
    题意:输入 1 a:询问是不是有连续长度为a的空房间,有的话住进最左边
            输入 2 a b:将[a,a+b-1]的房间清空
    线段树(区间合并):lsum[]统计从左端点起最长连续空房间数,rsum[]类似,sum[]统计区间最长连续的空房间数,
            它有三种情况:1.纯粹是左端点起的房间数;2.纯粹是右端点的房间数;3.当从左(右)房间起都连续时,加上另一个子节点
            从左(右)房间起的数,sum[]再求最大值更新维护。理解没错,表达能力不足
    详细解释:http://www.cnblogs.com/scau20110726/archive/2013/05/07/3065418.html
*/
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
const int MAXN = 5e4 + 10;
const int INF = 0x3f3f3f3f;
struct Segment_Tree {
    int sum[MAXN<<2], lsum[MAXN<<2], rsum[MAXN<<2], cover[MAXN<<2];
    void push_up(int rt, int len)    {
        lsum[rt] = lsum[rt<<1];
        rsum[rt] = rsum[rt<<1|1];
        if (lsum[rt] == len - (len>>1)) lsum[rt] += lsum[rt<<1|1];
        if (rsum[rt] == len>>1)   rsum[rt] += rsum[rt<<1];
        sum[rt] = max (rsum[rt<<1] + lsum[rt<<1|1], max (sum[rt<<1], sum[rt<<1|1]));
    }
    void push_down(int rt, int len) {
        if (cover[rt] != -1)    {
            cover[rt<<1] = cover[rt<<1|1] = cover[rt];
            sum[rt<<1] = lsum[rt<<1] = rsum[rt<<1] = cover[rt] ? 0 : len - (len>>1);
            sum[rt<<1|1] = lsum[rt<<1|1] = rsum[rt<<1|1] = cover[rt] ? 0 : len >> 1;
            cover[rt] = -1;
        }
    }
    void build(int l, int r, int rt)    {
        sum[rt] = lsum[rt] = rsum[rt] = r - l + 1;
        cover[rt] = -1;
        if (l == r) return ;
        int mid = (l + r) >> 1;
        build (lson);   build (rson);
    }
    void updata(int ql, int qr, int c, int l, int r, int rt)   {
        if (ql <= l && r <= qr) {
            sum[rt] = lsum[rt] = rsum[rt] = c ? 0 : (r - l + 1);
            cover[rt] = c;  return ;
        }
        push_down (rt, r - l + 1);
        int mid = (l + r) >> 1;
        if (ql <= mid)  updata (ql, qr, c, lson);
        if (qr > mid)   updata (ql, qr, c, rson);
        push_up (rt, r - l + 1);
    }
    int query(int w, int l, int r, int rt) {
        if (l == r) return l;
        push_down (rt, r - l + 1);
        int mid = (l + r) >> 1;
        if (sum[rt<<1] >= w)    return query (w, lson);
        else if (rsum[rt<<1] + lsum[rt<<1|1] >= w)  return mid - rsum[rt<<1] + 1;
        else    return query (w, rson);
    }
}st;

int main(void)  {       //POJ 3667 Hotel
    int n, m;
    while (scanf ("%d%d", &n, &m) == 2) {
        st.build (1, n, 1);
        for (int i=1; i<=m; ++i)    {
            int op, a, b; scanf ("%d%d", &op, &a);
            if (op == 1)    {
                if (st.sum[1] < a)  puts ("0");
                else    {
                    int p = st.query (a, 1, n, 1);
                    printf ("%d\n", p);
                    st.updata (p, p + a - 1, 1, 1, n, 1);
                }
            }
            else    {
                scanf ("%d", &b);
                st.updata (a, a + b - 1, 0, 1, n, 1);
            }
        }
    }

    return 0;
}

  

转载于:https://www.cnblogs.com/Running-Time/p/4686455.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值