POJ 3667 Hotel

经典类型,求一块满足条件的最左边的空间。成段更新


下面的代码有点冗余。

(代码里面stat标记整段线段是否为0/1/混合,但这里没必要,这里只需对整段线段置0或1操作打懒标记,记录此操作执行到哪里,方便下次如果要访问它的子区间时进行此操作)

#include <iostream>
#include <stdio.h>
using namespace std;

const int maxn = 50000 * 3;

struct Node
{
    int left, right;
    int stat;               // 0:区间全为0,1:区间全为1,2:区间有部分为0部分为1
    int lmax, rmax, amax;   // lmax:包含最左边元素最长0的长度,rmax:包含最右边元素最长0的长度
} tree[maxn];               // amax:区间中最长0的长度

void Build(int l, int r, int id)
{
    tree[id].left = l; tree[id].right = r;
    tree[id].stat = 0;
    tree[id].lmax = tree[id].rmax = tree[id].amax = r - l + 1;
    if (l == r) return;

    int m = (l + r) / 2;
    Build(l, m, id * 2);
    Build(m + 1, r, id * 2 + 1);
}

void UpdateStatus(int id)
{
    if (tree[id].stat == 2)
    {
        if (tree[id*2].stat == tree[id*2+1].stat && tree[id*2].stat != 2)
            tree[id].stat = tree[id*2].stat;
    }
}

void UpdateLength(int id)
{
    if (tree[id].stat == 0)
        tree[id].lmax = tree[id].rmax = tree[id].amax =tree[id].right - tree[id].left + 1;
    else if (tree[id].stat == 1)
        tree[id].lmax = tree[id].rmax = tree[id].amax = 0;
    else
    {
        tree[id].amax = max(max(tree[id*2].amax, tree[id*2+1].amax), tree[id*2].rmax + tree[id*2+1].lmax);
        tree[id].lmax = tree[id*2].lmax;
        tree[id].rmax = tree[id*2+1].rmax;
        if (tree[id*2].stat == 0)
            tree[id].lmax += tree[id*2+1].lmax;
        if (tree[id*2+1].stat == 0)
            tree[id].rmax += tree[id*2].rmax;
    }
}

void Update(int l, int r, int v, int id)    // v = 0:更新一段区间为0, v = 1:更新一段区间为1
{
    if (tree[id].stat == v)
        return;

    if (tree[id].left == l && tree[id].right == r)
    {
        tree[id].stat = v;
        UpdateLength(id);
        return;
    }
    if (tree[id].stat != 2)
    {
        tree[id*2].stat = tree[id*2+1].stat = tree[id].stat;
        tree[id].stat = 2;
        UpdateLength(id*2);
        UpdateLength(id*2+1);
    }
    int m = (tree[id].left + tree[id].right) / 2;
    if (r <= m)
        Update(l, r, v, id * 2);
    else if (l > m)
        Update(l , r, v, id * 2 + 1);
    else
        Update(l, m, v, id * 2), Update(m + 1, r, v, id * 2 + 1);
    UpdateStatus(id);
    UpdateLength(id);
}

int  Query(int len, int id)
{
    if (tree[id].stat == 0)
        return tree[id].left;
    if (tree[id*2].amax >= len)
        return Query(len, id * 2);
    else if (tree[id*2].rmax + tree[id*2+1].lmax >= len)
        return tree[id*2].right - tree[id*2].rmax + 1;
    else
        return Query(len, id * 2 + 1);
}

int main()
{
    int N, M;
    int cmd, len, x;

    scanf("%d %d", &N, &M);
    Build(1, N, 1);
    for (int i = 0; i < M; i++)
    {
        scanf("%d", &cmd);
        if (cmd == 1)
        {
            scanf("%d", &len);
            if (tree[1].amax < len)
                printf("0\n");
            else
            {
                x = Query(len, 1);
                Update(x, x + len - 1, 1, 1);
                printf("%d\n", x);
            }
        }
        else
        {
            scanf("%d %d", &x, &len);
            Update(x, x + len - 1, 0, 1);
        }
    }
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值