poj 3667 Hotel 线段树

来源:互联网 发布:免费进销存软件排名 编辑:程序博客网 时间:2024/05/21 16:34

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


题目大意:

        有N间房,排成一排,每次入住连续编号为[r, r + D - 1]的房间,要求r最小;每次退房时会退掉连续编号为[X, X + D - 1]的房间。输入有两种形式:

    1 入住D间房间,要求输出r最小

    2 退掉一段房间


题目分析:

    经典线段树问题。有插入、删除和查询操作。每次入住时查询并插入,退房时删除。

    可以通过维护左端空房数,右端空房数和最大空房数三个空间来实现各个操作。

具体实现过程:

    lf[]记录左端连续空房

    rf[]记录右端连续空房

    mf[]记录最长连续空房

    dl[]标记该段房间的状态,也就是懒操作:0为空,1为满

    update()实现对一段区间的更新

    pushdown()使标记下传

    query()查询最左所需连续房间编号


实现代码:

#include <stdio.h>#include <stdlib.h>#include <string.h>#define maxn 50002<<2#define m ((l+r)>>1)#define ll (t<<1) // 左孩子#define rr (t<<1|1) // 右孩子#define ls l,m,ll // 左孩子参数#define rs m+1,r,rr //右孩子参数#define max(a,b) ((a)>(b)?(a):(b))int lf[maxn], rf[maxn], mf[maxn], dl[maxn];inline void pushdown(int l, int r, int t) { // 标记下传if (dl[t] != -1) {lf[ll] = rf[ll] = mf[ll] = (dl[ll] = dl[t]) ? 0 : (m - l + 1);lf[rr] = rf[rr] = mf[rr] = (dl[rr] = dl[t]) ? 0 : (r - m);dl[t] = -1;}}void update(int L, int R, int c, int l, int r, int t) {if (L <= l && r <= R) {lf[t] = rf[t] = mf[t] = (dl[t] = c) ? 0 : (r - l + 1);return;}pushdown(l, r, t);if (L <= m)update(L, R, c, ls);if (R > m)update(L, R, c, rs);// pushuplf[t] = lf[ll];rf[t] = rf[rr];if (lf[ll] == m - l + 1)lf[t] += lf[rr];if (rf[rr] == r - m)rf[t] += rf[ll];mf[t] = max(max(mf[ll], mf[rr]), rf[ll] + lf[rr]);}int query(int d, int l, int r, int t) { // 查询过程if (l == r)return l;pushdown(l, r, t); // 不要忘了标记下传if (mf[ll] >= d)return query(d, ls);else if (rf[ll] + lf[rr] >= d)return m - rf[ll] + 1;elsereturn query(d, rs);}int main() {int n, cs, c, d, x, p;scanf("%d %d", &n, &cs);// 建树lf[1] = rf[1] = mf[1] = n;dl[1] = 0;while (cs--) {scanf("%d", &c);if (c == 1) {scanf("%d", &d);if (d > mf[1])printf("0\n");else {p = query(d, 1, n, 1);printf("%d\n", p);update(p, p + d - 1, 1, 1, n, 1);}} else {scanf("%d %d", &x, &d);update(x, x + d - 1, 0, 1, n, 1);}}return 0;}




原创粉丝点击