题意:在一个酒店里有一排房间从1到N标号,游客们要来住店,对于这些房间有两种操作,一种是查询有没有连续的n间房间,有的话就返回最小的房间号并标记入住,没有就返回0,另一种操作就是取消连续的房间a到b的入住。
线段树的基本题型,利用区间的合并就可解决。对于线段树中的每个节点需要记录区间范围[L,R],区间从左起连续的房间数lsum,区间从右边起连续的房间数rsum,区间最大的连续房间数sum,还有就是懒惰标记d(其中1表示入住,0表示取消入住,-1表示没有更新消息)。
代码:
#include <iostream>
#include <cstdio>
using namespace std;
#define maxn 55555
struct node
{
int l, r, lsum, rsum, sum, d;
}v[maxn*4];
void build (int l, int r, int n)
{
v[n].l = l;
v[n].r = r;
v[n].lsum = v[n].rsum = v[n].sum = r-l+1;
v[n].d = -1;
if (l==r)
return ;
int mid = (v[n].l + v[n].r) >> 1;
build(l, mid, n<<1);
build(mid+1, r, n<<1|1);
}
void pushdown(int n)
{
if (v[n].d!=-1)
{
int t = v[n].r-v[n].l+1;
v[n<<1].lsum = v[n<<1].rsum = v[n<<1].sum = v[n].d?0:t-(t>>1);
v[n<<1|1].lsum = v[n<<1|1].rsum = v[n<<1|1].sum = v[n].d?0:(t>>1);
v[n<<1].d = v[n<<1|1].d = v[n].d;
v[n].d = -1;
}
}
void pushup(int n)
{
v[n].lsum = v[n<<1].lsum;
v[n].rsum = v[n<<1|1].rsum;
int t = v[n].r-v[n].l+1;
if (v[n].lsum == t-(t>>1))
v[n].lsum += v[n<<1|1].lsum;
if (v[n].rsum == t>>1)
v[n].rsum += v[n<<1].rsum;
v[n].sum = max( v[n<<1].sum, max( v[n<<1|1].sum, v[n<<1].rsum+v[n<<1|1].lsum ) );
}
void update(int l, int r, int d, int n)
{
if (l<=v[n].l && v[n].r<=r)
{
v[n].lsum = v[n].rsum = v[n].sum = d?0:r-l+1;
v[n].d = d;
return ;
}
pushdown(n);
int mid = (v[n].l+v[n].r)>>1;
if (r<=mid)
update(l, r, d, n<<1);
else if (l>mid)
update(l, r, d, n<<1|1);
else
{
update(l, mid, d, n<<1);
update(mid+1, r, d, n<<1|1);
}
pushup(n);
}
int query(int w, int n)
{
pushdown(n);
int mid = (v[n].l+v[n].r)>>1;
if (v[n<<1].sum>=w)
return query(w, n<<1);
else if (v[n<<1].rsum+v[n<<1|1].lsum>=w)
return mid-v[n<<1].rsum+1;
else
return query(w, n<<1|1);
}
int main()
{
int n, m, op, a, b;
while (~scanf("%d%d", &n, &m))
{
build(1, n, 1);
while (m--)
{
scanf("%d", &op);
if (op==1)
{
scanf("%d", &a);
if (v[1].sum<a)
printf("0\n");
else
{
int t = query(a, 1);
printf("%d\n", t);
update(t, a+t-1, 1, 1);
}
}
else
{
scanf("%d%d", &a, &b);
update(a, a+b-1, 0, 1);
}
}
}
return 0;
}