POJ-Hotel

11 篇文章 0 订阅
4 篇文章 0 订阅

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.

Input

  • 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 Di (b) Three space-separated integers representing a check-out: 2, Xi, and Di

Output

  • 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.

Sample Input

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

Sample Output

1
4
7
0
5

题目大意

参考样例,第一行输入n,m ,n代表有n个房间,编号为1—n,开始都为空房,m表示以下有m行操作,以下 每行先输入一个数 i ,表示一种操作:

若i为1,表示查询房间,再输入一个数x,表示在1–n 房间中找到长度为x的连续空房,输出连续x个房间中左端的房间号,尽量让这个房间号最小,若找不到长度为x的连续空房,输出0。若找得到,在这x个空房间中住上人。

若i为2,表示退房,再输入两个数 x,y 代表 房间号 x—x+y-1 退房,即让房间为空。

解题思路

首先可以确定这是一个区间修改单点查询的问题,那么就要用到线段树的延迟操作
这里他有两个区间的查询操作,一个是退房一个是入房,那么我们的lazy就标记为两种,根据题意咱们设定lazy=1时是入房,lazy=2时是退房
我们这里维护的是三个参数,一个是区间左侧可空出的房间最大值,一个是区间右侧可空出房间最大值,一个是这个区间可以空出的房间的最大值。
代码一共需要分为creat,pushup,pushdown,update,query这5步操作。
那么接下来我们一起来探究一下,这五个操作如何去维护这三个操作。
首先我们应当构造一个结构体,里面包含三个参数并且包含lazy标记。

const int N = 100000;
struct node {
	ll sum, rmaxn, lmaxn;
	int lazy;
}tree[N * 4 + 7];

1. creat

先上代码

void creat(int l, int r, int rt)
{
	int len = r - l + 1;
	int mid = l + r >> 1;
	tree[rt] = node{ len,len,len,0 };
	if (l == r)return;
	creat(l, mid, rt << 1);
	creat(mid + 1, r, rt << 1 | 1);
}

creat的作用很显然就是初始化这棵树,那么这棵树包含的信息有什么呢?

  1. 左最值
  2. 右最值
  3. 整体最大值
  4. lazy标记

因为最初房间都是空的,所以可用的范围都是区间长度,既r-l+1
最初都没有lazy标记
接着深搜构造这棵线段树

2.pushup

void push_up(int l, int r, int rt)
{
	int mid = l + r >> 1;
	if (tree[rt << 1].sum == mid - l + 1)
		tree[rt].lmaxn = tree[rt << 1].sum + tree[rt << 1 | 1].lmaxn;
	else
		tree[rt].lmaxn = tree[rt << 1].lmaxn;
	if (tree[rt << 1 | 1].sum == r - mid)
		tree[rt].rmaxn = tree[rt << 1 | 1].sum + tree[rt << 1].rmaxn;
	else
		tree[rt].rmaxn = tree[rt << 1 | 1].rmaxn;
	tree[rt].sum = tree[rt << 1].rmaxn + tree[rt << 1 | 1].lmaxn;
	tree[rt].sum = max(tree[rt << 1 | 1].sum, max(tree[rt << 1].sum, tree[rt].sum));
}

我们想一下,pushup的操作是操作进入回溯阶段,父亲节点根据左右子节点去重新维护自己的值的过程。

在这里插入图片描述
自己的左最值可以是自己的左孩子加右孩子的左侧,前提是左孩子的整个区间都是空房间
否则只能是左孩子的左最值
同理
自己的左最值可以是自己的右孩子加左孩子的右侧,前提是右孩子的整个区间都是空房间
否则只能是右孩子的右最值
在这里插入图片描述
下面该维护整个区间的最大值了,我们可以知道,整个区间的最大值可以由左孩子和右孩子的最大值来决定,这是数据原来就有的数据,但是合并之后就会出现一个新的数据,那就是左孩子的右最值和右孩子的左最值。

在这里插入图片描述

3. pushdown

void push_down(int l, int r, int rt)
{
	int mid = l + r >> 1;
	if (tree[rt].lazy)
	{
		if (tree[rt].lazy == 1)
		{
			tree[rt << 1].lazy = tree[rt << 1 | 1].lazy = 1;
			tree[rt << 1].lmaxn = tree[rt << 1].rmaxn = tree[rt << 1].sum = 0;
			tree[rt << 1 | 1].lmaxn = tree[rt << 1 | 1].rmaxn = tree[rt << 1 | 1].sum = 0;
		}
		else
		{
			tree[rt << 1].lazy = tree[rt << 1 | 1].lazy = 2;
			tree[rt << 1].lmaxn = tree[rt << 1].rmaxn = tree[rt << 1].sum = mid - l + 1;
			tree[rt << 1 | 1].lmaxn = tree[rt << 1 | 1].rmaxn = tree[rt << 1 | 1].sum = r - mid;
		}
		tree[rt].lazy = 0;
	}
}

pushdown操作主要是传递lazy标记的操作,同时把状态下压。
如果当前的标记为入房,那么下传后的标记的三个参数的值应该都为0,因为没有房间可以入住
如果当前的标记为退房,那么下传后的标记的三个参数的值都应该是这个区间的长度,因为所有房间都可以入住。
最后把当前节点的lazy标记计为0.

4. update

void update(int L, int R, int mark, int l, int r, int rt)
{
	if (L <= l && r <= R)
	{
		if (mark == 1)
			tree[rt].sum = tree[rt].lmaxn = tree[rt].rmaxn = 0;
		else
			tree[rt].sum = tree[rt].lmaxn = tree[rt].rmaxn = r - l + 1;
		tree[rt].lazy = mark;
		return;
	}
	if (tree[rt].lazy)push_down(l, r, rt);
	int mid = l + r >> 1;
	if (L <= mid)update(L, R, mark, l, mid, rt << 1);
	if (R > mid)update(L, R, mark, mid + 1, r, rt << 1 | 1);
	push_up(l, r, rt);
}

如果当前的区间完全属于目标区间,那么这个区间整体加lazy标记,否则的话,就判断目标区间和当前区间的关系,去递归这个区间关系。经过非包含的点的时候要下压lazy标记
最后一直向下修改之后,返回时要pushup操作。

5. query

ll query(int len, int l, int r, int rt)
{
	if (l == r)return l;
	if (tree[rt].lazy)push_down(l, r, rt);
	int mid = l + r >> 1;
	if (tree[rt << 1].sum >= len)return query(len, l, mid, rt << 1);
	if (tree[rt << 1].rmaxn + tree[rt << 1 | 1].lmaxn >= len)return mid - tree[rt << 1].rmaxn + 1;
	return query(len, mid + 1, r, rt << 1 | 1);
}

查询过程中,如果当前区间的l和r相等那么就表示查询到头了,一般情况下,这是对于长度为1的情况的处理方法,因为只有查询区间长度为1才会走到叶子节点。
否则的话,我们如果存在lazy标记,那么我们下压标记。
那么我们继续来看下面三种情况。我们优先去查询靠左的区间,

  1. 如果判断出左孩子的最大值依然能够放入整个区间,那么继续遍历左区间。
  2. 如果左边已经不能满足,那么就看左孩子的右最值和右孩子的左最值能否满足,如果能满足则可以很快的计算出当前合并的区间的左值,就是当前中间的下标减去左孩子右区间长度,因为是长度原因,还需要加上1,这样才能算出下标。
  3. 首先通过第一个节点的最值就能判断出能不能找到一个合适的区间,满足条件,如果说第一个节点满足那么接下来一定也有满足的,那么左边和中间都不能满足那么就只能在右边了。

我们依次查询这三种状态就可以得到最左侧满足的下标了。

AC代码

//#include<unordered_map>
#include<algorithm>
#include<iostream>
#include<string.h>
#include <iomanip>
#include<stdio.h>
#include<vector>
#include<string>
#include<math.h>
#include<cmath>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll ll_inf = 9223372036854775807;
const int int_inf = 2147483647;
const short short_inf = 32767;
const ll less_inf = 0x3f3f3f3f;
const char char_inf = 127;
#pragma GCC optimize(2)
#define accelerate cin.tie(NULL);cout.tie(NULL);ios::sync_with_stdio(false);
#define PI 3.141592653589793
#define EPS 1.0e-8
ll gcd(ll a, ll b) {
	return b ? gcd(b, a % b) : a;
}
ll lcm(ll a, ll b) {
	return a * b / gcd(a, b);
}
inline ll read() {
	ll c = getchar(), Nig = 1, x = 0;
	while (!isdigit(c) && c != '-')c = getchar();
	if (c == '-')Nig = -1, c = getchar();
	while (isdigit(c))x = ((x << 1) + (x << 3)) + (c ^ '0'), c = getchar();
	return Nig * x;
}
inline void out(ll a) {
	if (a < 0)putchar('-'), a = -a;
	if (a > 9)out(a / 10);
	putchar(a % 10 + '0');
}
ll qpow(ll x, ll n, ll mod) {
	ll res = 1;
	while (n > 0) {
		if (n & 1)res = (res * x) % mod;
		x = (x * x) % mod;
		n >>= 1;
	}
	return res;
}
#define read read()
const int N = 100000;
struct node {
	ll sum, rmaxn, lmaxn;
	int lazy;
}tree[N * 4 + 7];
void creat(int l, int r, int rt)
{
	int len = r - l + 1;
	int mid = l + r >> 1;
	tree[rt] = node{ len,len,len,0 };
	if (l == r)return;
	creat(l, mid, rt << 1);
	creat(mid + 1, r, rt << 1 | 1);
}

void push_up(int l, int r, int rt)
{
	int mid = l + r >> 1;
	if (tree[rt << 1].sum == mid - l + 1)
		tree[rt].lmaxn = tree[rt << 1].sum + tree[rt << 1 | 1].lmaxn;
	else
		tree[rt].lmaxn = tree[rt << 1].lmaxn;
	if (tree[rt << 1 | 1].sum == r - mid)
		tree[rt].rmaxn = tree[rt << 1 | 1].sum + tree[rt << 1].rmaxn;
	else
		tree[rt].rmaxn = tree[rt << 1 | 1].rmaxn;
	tree[rt].sum = tree[rt << 1].rmaxn + tree[rt << 1 | 1].lmaxn;
	tree[rt].sum = max(tree[rt << 1 | 1].sum, max(tree[rt << 1].sum, tree[rt].sum));
}
void push_down(int l, int r, int rt)
{
	int mid = l + r >> 1;
	if (tree[rt].lazy)
	{
		if (tree[rt].lazy == 1)
		{
			tree[rt << 1].lazy = tree[rt << 1 | 1].lazy = 1;
			tree[rt << 1].lmaxn = tree[rt << 1].rmaxn = tree[rt << 1].sum = 0;
			tree[rt << 1 | 1].lmaxn = tree[rt << 1 | 1].rmaxn = tree[rt << 1 | 1].sum = 0;
		}
		else
		{
			tree[rt << 1].lazy = tree[rt << 1 | 1].lazy = 2;
			tree[rt << 1].lmaxn = tree[rt << 1].rmaxn = tree[rt << 1].sum = mid - l + 1;
			tree[rt << 1 | 1].lmaxn = tree[rt << 1 | 1].rmaxn = tree[rt << 1 | 1].sum = r - mid;
		}
		tree[rt].lazy = 0;
	}
}
void update(int L, int R, int mark, int l, int r, int rt)
{
	if (L <= l && r <= R)
	{
		if (mark == 1)
			tree[rt].sum = tree[rt].lmaxn = tree[rt].rmaxn = 0;
		else
			tree[rt].sum = tree[rt].lmaxn = tree[rt].rmaxn = r - l + 1;
		tree[rt].lazy = mark;
		return;
	}
	if (tree[rt].lazy)push_down(l, r, rt);
	int mid = l + r >> 1;
	if (L <= mid)update(L, R, mark, l, mid, rt << 1);
	if (R > mid)update(L, R, mark, mid + 1, r, rt << 1 | 1);
	push_up(l, r, rt);
}
ll query(int len, int l, int r, int rt)
{
	if (l == r)return l;
	if (tree[rt].lazy)push_down(l, r, rt);
	int mid = l + r >> 1;
	if (tree[rt << 1].sum >= len)return query(len, l, mid, rt << 1);
	if (tree[rt << 1].rmaxn + tree[rt << 1 | 1].lmaxn >= len)return mid - tree[rt << 1].rmaxn + 1;
	return query(len, mid + 1, r, rt << 1 | 1);
}
int main()
{
	int n = read, m = read;
	creat(1, n, 1);
	while (m--)
	{
		int mark = read;
		if (mark == 1)
		{
			int len = read;
			if (tree[1].sum >= len)
			{
				ll l = query(len, 1, n, 1);
				out(l);
				puts("");
				update(l, l + len - 1, 1, 1, n, 1);
			}
			else
				puts("0");
		}
		else
		{
			int sta = read, len = read;
			update(sta, sta + len - 1, 2, 1, n, 1);
		}
	}
}

By-Round Moon

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Round moon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值