CodeForces 46D Parking Lot(线段树区间合并)

题意:

有一条长度为L的街道,有N个操作,现在有两种操作:
(1)”1 a”,表示有一辆长度为a的车开进来想找停车位;
停车位必须满足与它前面的车距离至少为b,与后面的车距离至少为f;
如果能找到这样的停车位,输出这辆车的起始位置(且这个位置最小),否则输出-1;
(2)”2 a”,表示第a个事件里进来停车的那辆车开出去了;

解析:

这题和POJ 3677 Hotel差不多,都是寻找连续的空位。
不过要注意第一辆车是不需要考虑前方车距的,最后一辆车不需要后方车距。
我们可以把街道长度扩充为 L+b+f 即可,假设车长为 x ,那么每次查询长度大于等于x+b+f的空位就行了。

my code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define ls (o<<1)
#define rs (o<<1|1)
#define lson ls, L, M
#define rson rs, M+1, R
#define MID (L + R) >> 1
#define LEN(L, R) ((R) - (L) + 1)
#define pb push_back
using namespace std;
typedef pair<int, int> pii;
const int N = 100105;

int cov[N<<2];
int mx[N<<2], mxL[N<<2], mxR[N<<2];

vector<pii> list;

void maintain(int o, int L, int R, int val) {
    cov[o] = val;
    mx[o] = mxL[o] = mxR[o] = val * LEN(L, R);
}

void pushUp(int o, int L, int R) {
    int M = MID;

    mxL[o] = mxL[ls], mxR[o] = mxR[rs];
    mx[o] = max(mx[ls], max(mx[rs], mxR[ls] + mxL[rs]));

    if(mxL[ls] == LEN(L, M)) mxL[o] += mxL[rs];
    if(mxR[rs] == LEN(M+1, R)) mxR[o] += mxR[ls];

    if(cov[ls] == cov[rs])
        cov[o] = cov[ls];
    else cov[o] = -1;
}

void pushDown(int o, int L, int R) {
    if(cov[o] != -1) {
        int M = MID;
        maintain(lson, cov[o]);
        maintain(rson, cov[o]);
        cov[o] = -1;
    }
}

void build(int o, int L, int R) {
    cov[o] = -1;
    if(L == R) {
        maintain(o, L, R, 1);
        return ;
    }
    int M = MID;
    build(lson);
    build(rson);
    pushUp(o, L, R);
}

int query(int o, int L, int R, int need) {
    if(L == R) return L;
    int M = MID;
    pushDown(o, L, R);
    if(mx[ls] >= need)
        return query(lson, need);
    else if(mxR[ls] + mxL[rs] >= need)
        return M - mxR[ls] + 1;
    else
        return query(rson, need);
}

void modify(int o, int L, int R, int ql, int qr, int val) {
    if(ql <= L && R <= qr) {
        maintain(o, L, R, val);
        return ;
    }
    int M = MID;
    pushDown(o, L, R);
    if(ql <= M) modify(lson, ql, qr, val);
    if(qr > M) modify(rson, ql, qr, val);
    pushUp(o, L, R);
}

int n, m;
int main() {
    int L, b, f;
    int op, x, ql, qr;
    int start;
    while(~scanf("%d%d%d", &L, &b, &f)) {

        list.clear();
        n = L + b + f;
        build(1, 0, n);

        scanf("%d", &m);
        while(m--) {
            scanf("%d%d", &op, &x);
            if(op == 1) {
                int need = x + b + f;

                start = query(1, 0, n, need);
                ql = start + b, qr = ql + x - 1;
                list.pb(make_pair(ql, qr));

                if(b <= ql && qr < b + L) {
                    printf("%d\n", start);
                    modify(1, 0, n, ql, qr, 0);
                }else {
                    puts("-1");
                }
            }else {
                ql = list[x-1].first, qr = list[x-1].second;
                list.pb(make_pair(ql, qr));
                modify(1, 0, n, ql, qr, 1);
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值