Hotel POJ - 3667 (线段树维护连续0的长度)

题目链接:http://poj.org/problem?id=3667

题意:给你一些空房子,有一些人来住房子,每次询问m个人能不能住上,需要住连续的空房子

空房子用0表示,被占用的房子用1表示,然后用线段树维护一个区间的最长连续0的长度,左连续,右连续

区间合并的时候,最长的连续0的长度,从三个值里取最大值,max(左儿子的最大值,右儿子的最大值,左儿子的最长右连续+右儿子的最长左连续)

具体看代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define ll long long

using namespace std;

const int maxn = 50000 + 10;
struct node{
    int l, r, lazy, maxx;
    int maxl, maxr, len;
}e[maxn << 2];

void build(int l, int r, int cur) {
    e[cur].l = l;
    e[cur].r = r;
    e[cur].lazy = 0;
    e[cur].len = e[cur].maxx = e[cur].maxl = e[cur].maxr = r - l + 1;
    if(l == r){
        return;
    }
    int mid = l + r >> 1;
    build(l, mid, cur << 1);
    build(mid + 1, r, cur << 1 | 1);
}

void pushup(int cur){
    //cout <<e[cur << 1].maxl <<"  "<<e[cur << 1].maxr << "  "<<e[cur << 1 | 1].maxl <<"  "<<e[cur << 1 |1].maxr<<endl;
    e[cur].maxl = e[cur << 1].maxl;
    e[cur].maxr = e[cur << 1 | 1].maxr;
    if(e[cur << 1].maxl == e[cur << 1].len) e[cur].maxl = e[cur << 1].len + e[cur << 1 | 1].maxl;
    if(e[cur << 1 | 1].maxr == e[cur << 1 | 1].len) e[cur].maxr = e[cur << 1].maxr + e[cur << 1 | 1].len;
    e[cur].maxx = max(e[cur << 1].maxx, max(e[cur << 1 | 1].maxx, e[cur << 1].maxr + e[cur << 1 | 1].maxl));
}

void pushdown(int cur){
    if(e[cur].lazy != 0){
        if(e[cur].lazy == 1){
            e[cur << 1].lazy = e[cur << 1 | 1].lazy = 1;
            e[cur << 1].maxx = e[cur << 1].maxl = e[cur << 1].maxr = 0;
            e[cur << 1 | 1].maxx = e[cur << 1 | 1].maxl = e[cur << 1 | 1].maxr = 0;
            e[cur].lazy = 0;
        }
        else {
            e[cur << 1].lazy = e[cur << 1 | 1].lazy = -1;
            e[cur << 1].maxx = e[cur << 1].maxl = e[cur << 1].maxr = e[cur << 1].len;
            e[cur << 1 | 1].maxx = e[cur << 1 | 1].maxl = e[cur << 1 | 1].maxr = e[cur << 1 | 1].len;
            e[cur].lazy = 0;
        }
    }
}

void update(int l, int r, int cur, int cl, int cr, int val){
    if(cl <= l && r <= cr){
        //cout << l << "  "<<r << "  "<<cur << endl;
        e[cur].lazy = val;
        if(val == 1)
            e[cur].maxl = e[cur].maxr = e[cur].maxx = 0;
        else
            e[cur].maxl = e[cur].maxr = e[cur].maxx = e[cur].len;
        return;
    }
    pushdown(cur);
    //cout << l << "  "<< r<<"  "<< cur <<endl;
    int mid = l + r >> 1;
    if(cl <= mid) update(l, mid , cur << 1, cl, cr, val);
    if(cr > mid) update(mid + 1, r, cur << 1 | 1, cl, cr ,val);
    pushup(cur);
    //cout << "e[cur].maxx = "<<e[cur].maxx << endl;
}

int query(int l, int r, int cur, int val) {
    if(l == r) {
        return l;
    }
    pushdown(cur);
    int mid = l + r >> 1;
    if(e[cur << 1].maxx >= val) return query(l, mid, cur << 1, val);
    else if(e[cur << 1].maxr + e[cur << 1 | 1].maxl >= val) return e[cur << 1 | 1].l + val - e[cur << 1].maxr - 1;
    else   return query(mid + 1, r, cur << 1 | 1, val);
}

int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    build(1, n, 1);
    while(m--) {
        int op, x, d;
        scanf("%d%d", &op, &x);
        if(op == 1) {
            if(e[1].maxx < x) {
                printf("0\n");
            }
            else {
                int l = query(1, n, 1, x);
                printf("%d\n", l - x + 1);
                update(1, n, 1, l - x + 1, l, 1);
            }
        }
        else {
            scanf("%d", &d);
            update(1, n, 1, x, x + d - 1, -1);
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值