zoukankan      html  css  js  c++  java
  • [POJ3667]Hotel

    [POJ3667]Hotel

    试题描述

    The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lake Superior. Bessie, ever the competent travel agent, has named the Bullmoose Hotel on famed Cumberland Street as their vacation residence. This immense hotel has N (1 ≤ N ≤ 50,000) rooms all located on the same side of an extremely long hallway (all the better to see the lake, of course).

    The cows and other visitors arrive in groups of size Di (1 ≤ Di ≤ N) and approach the front desk to check in. Each group i requests a set of Di contiguous rooms from Canmuu, the moose staffing the counter. He assigns them some set of consecutive room numbers r..r+Di-1 if they are available or, if no contiguous set of rooms is available, politely suggests alternate lodging. Canmuu always chooses the value of r to be the smallest possible.

    Visitors also depart the hotel from groups of contiguous rooms. Checkout i has the parameters Xi and Di which specify the vacating of rooms Xi ..Xi +Di-1 (1 ≤ Xi ≤ N-Di+1). Some (or all) of those rooms might be empty before the checkout.

    Your job is to assist Canmuu by processing M (1 ≤ M < 50,000) checkin/checkout requests. The hotel is initially unoccupied.

    输入

    * Line 1: Two space-separated integers: N and M
    * Lines 2..M+1: Line i+1 contains request expressed as one of two possible formats: (a) Two space separated integers representing a check-in request: 1 and D(b) Three space-separated integers representing a check-out: 2, Xi, and Di

    输出

    * Lines 1.....: For each check-in request, output a single line with a single integer r, the first room in the contiguous sequence of rooms to be occupied. If the request cannot be satisfied, output 0.

    输入示例

    10 6
    1 3
    1 3
    1 3
    1 3
    2 5 5
    1 6

    输出示例

    1
    4
    7
    0
    5

    数据规模及约定

    见“试题描述”

    题解

    对于每一个位置我们维护它所在的极长空区间。在查询的时候我们搞一个线段树,维护一下每个区间里面的极长空区间长度的最大值,然后我们看如果当前最大值小于询问长度就输出 0,线段树左边的最大值大于等于询问的长度就往左走,否则往右走,知道走到叶节点我们就找到这个位置了;然后我们需要把找到的这一段区间覆盖成非空状态,然后更新一下这段区间后面部分的极长区间信息,如下图:

    红色部分就是即将被改成非空状态的区间,绿色部分就是需要更新极长区间信息的部分(极长区间由红绿区间的并变成了绿色区间)

    对于第二种操作,我们查询一下左端点 - 1 的极长区间的左端点 ql,右端点 + 1 的极长区间的右端点 qr(注意如果左端点不在极长区间内 ql = 左端点,右端点同理),然后 [ql, qr] 就是一个新的极长区间了。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 50010
    
    int n, maxl[maxn<<2];
    struct Int {
    	int l, len;
    	Int(): l(-1), len(-1) {}
    	Int(int _, int __): l(_), len(__) {}
    } line[maxn], setv[maxn<<2];
    void build(int o, int l, int r) {
    	if(l == r) line[l] = Int(1, n), maxl[o] = n;
    	else {
    		int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
    		build(lc, l, mid); build(rc, mid + 1, r);
    		maxl[o] = max(maxl[lc], maxl[rc]);
    	}
    	return ;
    }
    void pushdown(int o, int l, int r) {
    	if(setv[o].l < 0) return ;
    	if(l == r){ setv[o] = Int(-1, -1); return ; }
    	int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
    	setv[lc] = setv[rc] = setv[o]; maxl[lc] = maxl[rc] = setv[o].len;
    	if(l == mid) line[l] = setv[o];
    	if(mid + 1 == r) line[r] = setv[o];
    	setv[o] = Int(-1, -1);
    	return ;
    }
    void update(int o, int l, int r, int ql, int qr, Int v) {
    	if(ql > qr) return ;
    	pushdown(o, l, r);
    	if(ql <= l && r <= qr) {
    		setv[o] = v;
    		maxl[o] = v.len;
    		if(l == r) line[l] = setv[o];
    		return ;
    	}
    	int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
    	if(ql <= mid) update(lc, l, mid, ql, qr, v);
    	if(qr > mid) update(rc, mid + 1, r, ql, qr, v);
    	maxl[o] = max(maxl[lc], maxl[rc]);
    	return ;
    }
    Int query(int o, int l, int r, int x) {
    	pushdown(o, l, r);
    	if(l == r) return line[l];
    	int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
    	if(x <= mid) return query(lc, l, mid, x);
    	return query(rc, mid + 1, r, x);
    }
    int Query(int o, int l, int r, int mx) {
    	pushdown(o, l, r);
    	if(maxl[o] < mx) return 0;
    	if(l == r) return line[l].l;
    	int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
    	if(maxl[lc] >= mx) return Query(lc, l, mid, mx);
    	return Query(rc, mid + 1, r, mx);
    }
    
    int main() {
    	n = read(); int q = read();
    	build(1, 1, n);
    	while(q--) {
    		int tp = read();
    		if(tp == 1) {
    			int len = read(), ans = Query(1, 1, n, len);
    			printf("%d
    ", ans);
    			if(ans) {
    				Int li = query(1, 1, n, ans);
    //				printf("li: [%d, %d]
    ", li.l, li.l + li.len - 1);
    //				printf("change: [%d, %d] to zero
    ", ans, ans + len - 1);
    				update(1, 1, n, ans, ans + len - 1, Int(0, 0));
    //				printf("change: [%d, %d] to [%d, %d]
    ", ans + len, li.l + li.len - 1, ans + len, li.len - len);
    				update(1, 1, n, ans + len, li.l + li.len - 1, Int(ans + len, li.len - len));
    			}
    		}
    		else {
    			int ql = read(), len = read(), qr = ql + len - 1;
    			Int l = ql > 1 ? query(1, 1, n, ql - 1) : Int(1, 1), r = qr < n ? query(1, 1, n, qr + 1) : Int(n, 1);
    //			printf("l: [%d, %d]
    r: [%d, %d]
    ", l.l, l.l + l.len - 1, r.l, r.l + r.len - 1);
    			if(l.l) ql = l.l;
    			if(r.l) qr = r.l + r.len - 1;
    //			printf("[%d, %d]
    ", ql, qr);
    			update(1, 1, n, ql, qr, Int(ql, qr - ql + 1));
    		}
    	}
    	
    	return 0;
    }
    

    另一种方法就是线段树维护区间中最大的空串长度,最大后缀空串长度,最大前缀空串长度,剩下的就很简单了。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 50010
    
    int mxl[maxn<<2], setv[maxn<<2], pre[maxn<<2], suf[maxn<<2];
    void build(int o, int l, int r) {
    	mxl[o] = pre[o] = suf[o] = r - l + 1;
    	setv[o] = -1;
    	if(l == r) return ;
    	int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
    	build(lc, l, mid); build(rc, mid + 1, r);
    	return ;
    }
    void pushdown(int o, int l, int r) {
    	int lc = o << 1, rc = lc | 1;
    	if(setv[o] < 0) return ;
    	if(l == r){ setv[o] = -1; return ; }
    	setv[lc] = setv[rc] = setv[o];
    	if(setv[o]) mxl[lc] = mxl[rc] = pre[lc] = pre[rc] = suf[lc] = suf[rc] = 0;
    	else {
    		int mid = l + r >> 1;
    		mxl[lc] = pre[lc] = suf[lc] = mid - l + 1;
    		mxl[rc] = pre[rc] = suf[rc] = r - mid;
    	}
    	setv[o] = -1;
    	return ;
    }
    void update(int o, int l, int r, int ql, int qr, int v) {
    	pushdown(o, l, r);
    	if(ql <= l && r <= qr) {
    		setv[o] = v;
    		if(v) mxl[o] = pre[o] = suf[o] = 0;
    		else mxl[o] = pre[o] = suf[o] = r - l + 1;
    		return ;
    	}
    	int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
    	if(ql <= mid) update(lc, l, mid, ql, qr, v);
    	if(qr > mid) update(rc, mid + 1, r, ql, qr, v);
    	mxl[o] = max(suf[lc] + pre[rc], max(mxl[lc], mxl[rc]));
    	pre[o] = (pre[lc] == mid - l + 1 ? pre[lc] + pre[rc] : pre[lc]);
    	suf[o] = (suf[rc] == r - mid ? suf[rc] + suf[lc] : suf[rc]);
    	return ;
    }
    int query(int o, int l, int r, int len) {
    	pushdown(o, l, r);
    	if(mxl[o] < len) return 0;
    	if(l == r) return l;
    	int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
    	if(mxl[lc] >= len) return query(lc, l, mid, len);
    	if(suf[lc] + pre[rc] >= len) return mid - suf[lc] + 1;
    	return query(rc, mid + 1, r, len);
    }
    
    int main() {
    	int n = read(), q = read();
    	build(1, 1, n);
    	while(q--) {
    		int tp = read();
    		if(tp == 1) {
    			int len = read(), ans = query(1, 1, n, len);
    			printf("%d
    ", ans);
    			if(ans) update(1, 1, n, ans, ans + len - 1, 1);
    		}
    		else {
    			int l = read(), r = l + read() - 1;
    			update(1, 1, n, l, r, 0);
    		}
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    inner join(inner可省) 与 left join 之间的区别
    Jedis+Redis+spring缓存
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
    js中的blob,图片base64URL,file之间的关系
    批量压缩图片
    xhr 的 onpregress 监听上传数据的 已上传 和 总大小
    如何禁止浏览器 前进功能
    获取页面滚动高度
    bootstrap的字体设置
    忽略 文件夹下的所有node/modules
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6683960.html
Copyright © 2011-2022 走看看