2020.3.15 POJ3667 Hotel
问题描述
奶牛们正在以旅行至桑德贝(Thunder Bay,加拿大中部城市)的方式来增加自己的文化涵养,同时在阳光充沛的苏必利尔湖畔度过一个美好的假期。Bessie,一个能干的旅行代办人,把位于著名的Cumberland街的Bullmouse酒店作为它们旅行时的临时住所。这个巨大的酒店有N个房间,位于酒店极长的走廊的同一侧(全是湖景房)。
奶牛以及其他游客以一个个旅游团的方式来到酒店登记入住,每个旅游团的大小为D(1<=D<=N)。每个旅行团会向驼鹿Canmuu请求一段连续的房间入住。如果存在长度为Di的一串空房间,他会将房间r至r+Di-1这些房间安排给这个旅行团,否则他将会礼貌的建议它们另寻一个住处。Canmuu总会选择使r最小的那一段房间。
同时,住在一段连续房间内的游客们也会同时离开酒店。第i次结账用参数X和D表示,代表房间X至X+D-1的房间内的游客离开酒店。某些(或所有)房间可能为空。
你的任务是帮助Canmuu处理M次入住、离开操作。酒店内一开始没有人。
输入格式
输入的第一行包含两个整数N,M,表示房间数和操作数。
下面M行,每行代表一个操作。
若第一个数为1,则后面会跟着一个数D,表示一个人数为D的旅行团请求入住。
若第一个数为2,则后面会跟着两个数Xi,Di,表示住在房间Xi至Xi+Di-1的游客离开。
输出格式
对于每一个入住操作,输出一个数r,可以入住时为最小房间编号,否则为0。
样例输入
10 6
1 3
1 3
1 3
1 3
2 5 5
1 6
样例输出
1
4
7
0
5
数据规模和约定
\(N,M \leq 50000,1 \leq D \leq N,1 \leq X \leq N-D+1。\)
做法:
有修改有询问 \(\rightarrow\) 用数据结构维护(线段树)
对于每个区间维护最长连续0的个数tmax,为了维护tmax,需要从左端起的最长连续0个数lmax和从右端起的最长连续0个数rmax
\(tmax[k]=max(tmax[lc],tmax[rc],rmax[lc]+lmax[rc])\)
\(lmax[k]=lmax[lc] or siz[lc] + lmax[rc]\)
修改:对于每个区间维护懒标记cov
询问:若lc的tmax符合题意,则一直向左找;
若拼起来符合题意,则直接返回
否则一直向右找
代码:
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 50005;
int n, m, op, x, d;
int lmax[N << 2], rmax[N << 2], tmax[N << 2], cov[N << 2], siz[N << 2];
inline void pushup(int k)
{
lmax[k] = lmax[k << 1];
rmax[k] = rmax[k << 1 | 1];
tmax[k] = max(tmax[k << 1], max(tmax[k << 1 | 1], rmax[k << 1] + lmax[k << 1 | 1]));
if (lmax[k << 1] == siz[k << 1])
lmax[k] = lmax[k << 1] + lmax[k << 1 | 1];
if (rmax[k << 1 | 1] == siz[k << 1 | 1])
rmax[k] = rmax[k << 1 | 1] + rmax[k << 1];
}
inline void pushdown(int k)
{
if (cov[k] != -1)
{
cov[k << 1] = cov[k << 1 | 1] = cov[k];
if (cov[k] == 1)
{
tmax[k << 1] = lmax[k << 1] = rmax[k << 1] = 0;
tmax[k << 1 | 1] = lmax[k << 1 | 1] = rmax[k << 1 | 1] = 0;
}
else
{
tmax[k << 1] = lmax[k << 1] = rmax[k << 1] = siz[k << 1];
tmax[k << 1 | 1] = lmax[k << 1 | 1] = rmax[k << 1 | 1] = siz[k << 1 | 1];
}
cov[k] = -1;
}
}
inline void BuildTree(int k, int l, int r)
{
siz[k] = r - l + 1;
if (l == r)
{
lmax[k] = rmax[k] = tmax[k] = 1;
cov[k] = -1;
return ;
}
int mid = l + r >> 1;
BuildTree(k << 1, l, mid);
BuildTree(k << 1 | 1, mid + 1, r);
pushup(k);
}
inline void Update(int k, int l, int r, int L, int R, int x)
{
if (L <= l && r <= R)
{
cov[k] = x;
lmax[k] = rmax[k] = tmax[k] = x ? 0 : siz[k];
return ;
}
pushdown(k);
int mid = l + r >> 1;
if (L <= mid)
Update(k << 1, l, mid, L, R, x);
if (mid < R)
Update(k << 1 | 1, mid + 1, r, L, R, x);
pushup(k);
}
inline int Query(int k, int l, int r, int x)
{
if (l == r)
return l;
pushdown(k);
int mid = l + r >> 1;
if (tmax[k << 1] >= x)
return Query(k << 1, l, mid, x);
else if(rmax[k << 1] + lmax[k << 1 | 1] >= x)
return mid - rmax[k << 1] + 1;
else
return Query(k << 1 | 1, mid + 1, r, x);
}
int main()
{
ios::sync_with_stdio(false);
cin >> n >> m;
BuildTree(1, 1, n);
for (int i = 1; i <= m; ++i)
{
cin >> op;
if (op == 1)
{
cin >> d;
if (tmax[1] < d)
{
cout << 0 << endl;
continue ;
}
int pos = Query(1, 1, n, d);
cout << pos << endl;
Update(1, 1, n, pos, pos + d - 1, 1);
}
else
{
cin >> x >> d;
Update(1, 1, n, x, x + d - 1, 0);
}
}
return 0;
}