codeforces 46D Parking Lot(线段树模拟区间管理 or set模拟)

题意:
可以看成是 poj Hotel 那道题的加强版。
这里是找车位,还要考虑与前后车之间的距离。。
不过这里n只有100,用set,就成了水题啊。。。

思路:
1) 线段树
比起 Hotel 也就是多讨论几种情况吧。。

const int N = 100000 + 5;

struct Node {
    int len, l, r, m, tag; // 0 - no tag, 1 - free, 2 - occupied

    void upd(int x) {
        if ( x == 1 ) {
            l = r = m = len;
        }
        if ( x == 2 ) {
            l = r = m = 0;
        }
        tag = x;
    }
};

Node tr[N<<2];
int qL, qR;
#define lc o<<1
#define rc o<<1|1

void push_down(int o) {
    if ( tr[o].tag ) {
        tr[lc].upd(tr[o].tag);
        tr[rc].upd(tr[o].tag);
        tr[o].tag = 0;
    }
}

void push_up(int o) {
    tr[o].l = tr[lc].l;
    if ( tr[lc].l == tr[lc].len ) tr[o].l += tr[rc].l;

    tr[o].r = tr[rc].r;
    if ( tr[rc].r == tr[rc].len ) tr[o].r += tr[lc].r;

    tr[o].m = tr[lc].r + tr[rc].l;
    tr[o].m = max ( tr[o].m, max ( tr[lc].m, tr[rc].m ) );
}

int query(int o, int l, int r) {
    if ( tr[o].m < qL ) return -1;
    if ( l == r ) return l; // take care...
    int m = (l + r) >> 1, ret;
    push_down(o);
    if ( tr[lc].m >= qL )
        ret = query(lc, l, m);
    else if ( tr[lc].r + tr[rc].l >= qL ) {
        ret = m - tr[lc].r + 1;
    } else {
        ret = query(rc, m+1, r);
    }
    push_up(o);
    return ret;
}

void update(int o, int l, int r, int x) {
    if ( qL <= l && r <= qR ) {
        tr[o].upd(x);
        //cout << " upd: " << l << ' ' << r << " : " << tr[o].l << ' ' << tr[o].r << ' ' << tr[o].m << endl;
        return;
    }
    int m = (l + r) >> 1;
    push_down(o);
    if ( qL <= m )
        update(lc, l, m, x);
    if ( qR > m )
        update(rc, m+1, r, x);
    push_up(o);
    //cout << " upd: " << l << ' ' << r << " : " << tr[o].l << ' ' << tr[o].r << ' ' << tr[o].m << endl;
}

void build(int o, int l, int r) {
    int len = r - l + 1;
    tr[o] = (Node) {len, len, len, len, 0};
    if ( l != r ) {
        int m = (l + r) >> 1;
        build(lc, l, m); build(rc, m+1, r);
    }
}

int rec[N][2], L, b, f, n;

int search_space(int i, int car) {
    int id;

    if ( tr[1].m == L ) { // no car
        qL = car;
        id = query(1, 1, L);
        if ( id != -1 ) {
            rec[i][0] = id, rec[i][1] = id + car - 1;
            return id - 1;
        }
    }

    qL = car + f;
    if ( tr[1].l >= qL ) {
        id = 1;
        rec[i][0] = id, rec[i][1] = id + car - 1;
        return id - 1;
    }

    qL = car + b + f;
    id = query(1, 1, L);
    if ( id != -1 ) {
        id += b;
        rec[i][0] = id, rec[i][1] = id + car - 1;
        return id - 1;
    }

    qL = car + b;
    if ( tr[1].r >= qL ) {
        id = L - tr[1].r + b + 1;
        rec[i][0] = id, rec[i][1] = id + car - 1;
        return id - 1;
    }

    return -1;
}

int main() {
#ifdef _LOCA_ENV_
    freopen("input.in", "r", stdin);
#endif // _LOCA_ENV
    int x, y;
    scanf("%d%d%d%d", &L, &b, &f, &n);
    memset(rec, -1, sizeof(rec));
    build(1, 1, L);
    rep(i, 1, n) {
        scanf("%d%d", &x, &y);
        if ( x == 1 ) {
            int res = search_space(i, y);
            if ( res != -1 ) {
                qL = rec[i][0], qR = rec[i][1];
                update(1, 1, L, 2);
            }
            printf("%d\n", res);
        } else {
            qL = rec[y][0], qR = rec[y][1];
            update(1, 1, L, 1);
        }
    }
    return 0;
}

2)set模拟
set 维护车占的区间前后端点。
有个小技巧, 虚拟一个 -b 和 L + f 端点,情况就统一了。。

const int N = 100000 + 5;
int rec[N][2], L, b, f, n;
set<int> s;
set<int>::iterator fir, sec;

int search_space(int i, int car) {
    int len = car + b + f;
    for(fir = s.begin(); fir != s.end(); ++ fir) {
        sec = fir; ++ sec;
        if ( sec != s.end() && *sec - *fir >= len ) {
            int st = *fir + b;
            int ed = st + car;
            s.insert(st);
            s.insert(ed);
            rec[i][0] = st;
            rec[i][1] = ed;
            return st;
        }
        ++ fir;
    }
    return -1;
}

int main() {
#ifdef _LOCA_ENV_
    freopen("input.in", "r", stdin);
#endif // _LOCA_ENV
    int x, y;
    scanf("%d%d%d%d", &L, &b, &f, &n);
    memset(rec, -1, sizeof(rec));
    s.insert(-b); s.insert(L + f);
    rep(i, 1, n) {
        scanf("%d%d", &x, &y);
        if ( x == 1 ) {
            int res = search_space(i, y);
            printf("%d\n", res);
        } else {
            s.erase(rec[y][0]);
            s.erase(rec[y][1]);
        }
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值