POJ 3667 Hotel

题目大意

我用自己的话概括一下,给一段长为n的空区间,有2种操作,一种就是找到最左边长为w的连续的空区间并返回这段空区间最左边的区间号。另一种就是将从区间号a开头长度为b的这一段区间清空。

题目分析

这道题是关于线段树区间合并的基础题,不过自己想了很久,自己也写了十几篇的线段树的博客有了自己线段树的风格,其实个人感觉挺简约的,看着也挺舒服,感觉封装在结构体中挺丑的,什么都要加个前缀。
合并的时候需要处理的点挺多的,这里我就不一一列举了,详细的看我的代码。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define mid (L+R)/2
#define lson o<<1, L, mid
#define rson o<<1|1, mid+1, R
const int maxn = 50005;
int lsum[maxn<<2],rsum[maxn<<2],msum[maxn<<2];
int cover[maxn<<2]; // 延迟标记

void pushdown(int o,int m) //标记往下
{
    if(cover[o] != -1) //等于1表示这些房子住了,等于0表示住的人走了
    {
        cover[o<<1] = cover[o<<1|1] = cover[o];
        msum[o<<1] = lsum[o<<1] = rsum[o<<1] = cover[o]? 0 : m - (m >> 1);
        msum[o<<1|1] = lsum[o<<1|1] = rsum[o<<1|1] = cover[o] ? 0 : (m >> 1);
        cover[o] = -1;
    }
}

void pushup(int o,int m)  //这里大家可以仔细想一下,很容易理解
{
    lsum[o] = lsum[o<<1];
    rsum[o] = rsum[o<<1|1];
    if(lsum[o] == m-(m>>1)) lsum[o] += lsum[o<<1|1];
    if(rsum[o] == (m>>1))  rsum[o] += rsum[o<<1];
    msum[o] = max(rsum[o<<1]+lsum[o<<1|1], max(msum[o<<1], msum[o<<1|1]));
}

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

void update(int o,int L,int R,int l,int r,int c)
{
    if(l <= L && R <= r){
        msum[o] = lsum[o] = rsum[o] = c?0:R-L+1;
        cover[o] = c;
        return ;
    }
    pushdown(o, R-L+1);   //标记向下推移
    if(l <= mid) update(lson, l, r, c);
    if(mid < r) update(rson, l, r, c);
    pushup(o, R-L+1); //同时更新父亲结点的信息
}

int query(int o,int L,int R,int w) //返回最左边的能容纳长为w的区间的左端点,注意是找最左边
{
    if(L == R) return L;  //这一点不能掉了
    pushdown(o, R-L+1);
    if(msum[o<<1] >= w) return query(lson,w); //左区间有就到左孩子区间
    else if(rsum[o<<1] + lsum[o<<1|1] >= w) //处于左区间与右区间的中间
        return mid - rsum[o<<1] + 1;
    else
        return query(rson,w);  //只能找右区间了
}

int main()
{
    int n,m;
    scanf("%d%d", &n, &m);
    build(1, 1, n);
    while(m--){
        int op,a,b;
        scanf("%d", &op);
        if(op == 1)
        {
            scanf("%d", &a);
            if(msum[1] < a)  //如果根没有,那么一定没有
                printf("0\n");
            else{
                int p = query(1, 1, n, a);
                printf("%d\n", p);
                update(1, 1, n, p, p+a-1, 1);
            }
        }
        else
        {
            scanf("%d%d", &a, &b);
            update(1, 1, n, a, a+b-1, 0);
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值