首页 > 代码库 > [POJ3667]Hotel

[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\n", ans);
			if(ans) {
				Int li = query(1, 1, n, ans);
//				printf("li: [%d, %d]\n", li.l, li.l + li.len - 1);
//				printf("change: [%d, %d] to zero\n", ans, ans + len - 1);
				update(1, 1, n, ans, ans + len - 1, Int(0, 0));
//				printf("change: [%d, %d] to [%d, %d]\n", 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]\nr: [%d, %d]\n", 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]\n", ql, qr);
			update(1, 1, n, ql, qr, Int(ql, qr - ql + 1));
		}
	}
	
	return 0;
}

 

[POJ3667]Hotel