2017年8月16日提高组T3 旅馆

90 篇文章 0 订阅

Description


有一间旅馆,旅馆内有n间排成一排的房间,一开始全为空。现在有m个要求:
1 d表示询问旅馆内是否有连续d间空房间,有的话则输出最小的一个r,满足从r开始连续d间房间均为空,同时会有人入住这d间房。若无法被满足,则输出0.
2 l r表示把[l,r]内的房间全部设为空。

Input


第一行两个整数n,m.
接下来m行,每行描述一个操作。

Output


对于每一个1操作,输出一行表示答案。

Hint


【数据规模与约定】
对于30%的数据,n,m<=1000
对于100%的数据,n,m<=50000,d,l,r<=n

Source


BY BPM

Solution


线段树区间合并

考虑用llen、rlen、len分别记录区间左起最长连续0、右起最长连续0、最长连续0,查询的时候优先查询左子树即可。合并的时候分情况讨论一下就行了。

心疼基哥500行+程序wa了

Code


#include <stdio.h>
#include <string.h>
#include <math.h>
#include <queue>
#include <vector>
#include <algorithm>
#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)
#define drp(i, st, ed) for (int i = st; i >= ed; i -= 1)
#define erg(i, st) for (int i = ls[st]; i; i = e[i].next)
#define fill(x, t) memset(x, t, sizeof(x))
#define max(x, y) (x)>(y)?(x):(y)
#define min(x, y) (x)<(y)?(x):(y)
#define ll long long
#define db double
#define INF 0x3f3f3f3f
#define N 100001
struct treeNode{int l, r, llen, rlen, len, lazy;}t[N << 2 | 1];
inline int read() {
    int x=0,v=1; char ch=getchar();
    while (ch<'0'||ch>'9'){if(ch=='-')v=-1; ch=getchar();}
    while (ch<='9'&&ch>='0'){x=x*10+ch-'0'; ch=getchar();}
    return x*v;
}
inline void pushDown(int now) {
    if (t[now].lazy == 1) {
        t[now << 1].lazy = t[now << 1 | 1].lazy = 1;
        t[now << 1].llen = t[now << 1].rlen = t[now << 1].len = 0;
        t[now << 1 | 1].llen = t[now << 1 | 1].rlen = t[now << 1 | 1].len = 0;
        t[now].lazy = 0;
    }else if (t[now].lazy == 2) {
        t[now << 1].lazy = t[now << 1 | 1].lazy = 2;
        t[now << 1].llen = t[now << 1].rlen = t[now << 1].len = t[now << 1].r - t[now << 1].l + 1;
        t[now << 1 | 1].llen = t[now << 1 | 1].rlen = t[now << 1 | 1].len = t[now << 1 | 1].r - t[now << 1 | 1].l + 1;
        t[now].lazy = 0;
    }
}
inline void pushUp(int now) {
    if (t[now << 1].r - t[now << 1].l + 1 == t[now << 1].llen){
        t[now].llen = t[now << 1].llen + t[now << 1 | 1].llen;
    }else {
        t[now].llen = t[now << 1].llen;
    }
    if (t[now << 1 | 1].r - t[now << 1 | 1].l + 1 == t[now << 1 | 1].rlen){
        t[now].rlen = t[now << 1].rlen + t[now << 1 | 1].rlen;
    }else {
        t[now].rlen = t[now << 1 | 1].rlen;
    }
    t[now].len = max(t[now << 1].rlen + t[now << 1 | 1].llen, max(t[now << 1].len, t[now << 1 | 1].len));
}
inline int query(int now, int d) {
    pushDown(now);
    if (t[now].l == t[now].r) {
        return 1;
    }else if (t[now << 1].len >= d) {
        return query(now << 1, d);
    }else if (t[now << 1].rlen + t[now << 1 | 1].llen >= d) {
        return t[now << 1].r - t[now << 1].rlen + 1;
    }else {
        return query(now << 1 | 1, d);
    }
}
inline void modify(int now, int l, int r) {
    pushDown(now);
    if (t[now].l == l && t[now].r == r) {
        t[now].lazy = 1;
        t[now].llen = t[now].rlen = t[now].len = 0;
        return ;
    }
    int mid = (t[now].l + t[now].r) >> 1;
    if (r <= mid) {
        modify(now << 1, l, r);
    }else if (l > mid) {
        modify(now << 1 | 1, l, r);
    }else {
        modify(now << 1, l, mid);
        modify(now << 1 | 1, mid + 1, r);
    }
    pushUp(now);
}
inline void clear(int now, int l, int r) {
    pushDown(now);
    if (t[now].l == l && t[now].r == r) {
        t[now].lazy = 2;
        t[now].llen = t[now].rlen = t[now].len = t[now]. r - t[now].l + 1;
        return ;
    }
    int mid = (t[now].l + t[now].r) >> 1;
    if (r <= mid) {
        clear(now << 1, l, r);
    }else if (l > mid) {
        clear(now << 1 | 1, l, r);
    }else {
        clear(now << 1, l, mid);
        clear(now << 1 | 1, mid + 1, r);
    }
    pushUp(now);
}
inline void build(int now, int l, int r) {
    t[now] = (treeNode){l, r, r - l + 1, r - l + 1, r - l + 1};
    if (l == r){return ;}
    int mid = (t[now].l + t[now].r) >> 1;
    build(now << 1, l, mid);
    build(now << 1 | 1, mid + 1, r);
}
int main(void) {
    int n = read();
    int m = read();
    build(1, 1, n);
    while (m --) {
        int opt = read();
        if (opt == 1) {
            int d = read();
            if (d > t[1].len) {puts("0"); continue;}
            int pos = query(1, d); modify(1, pos, pos + d - 1);
            printf("%d\n", pos);
        } else if (opt == 2) {
            int l = read();
            int r = read();
            clear(1, l, r);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值