题目大意
有n个本来为空的房间,有两种操作。
1:找到最左边连续长为l的一段,并占有它们。
2:将l到r区间置为空。
Solution
我们可以用线段树维护一段区间内最多连续的空房间数。但只记下这个答案,是无法把两个区间合并的。而只要多记下这个区间从左开始连续空房间数,从右开始连续空房间数,就能把两个区间合并了。
询问时,我们可以在左右子树中分别寻找答案。但还要多考虑一种答案在两棵子树中的情况,这个答案是由左子树从右开始连续空房间数,右子树从左开始连续空房间数贡献的。二分时多讨论这种情况就可以了。
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int tag[1000010],tree[1000010],treel[1000010],treer[1000010];
void update(int t,int l,int r)
{
tree[t]=max(treel[t<<1|1]+treer[t<<1],max(tree[t<<1],tree[t<<1|1]));
treel[t]=treel[t<<1];
int mid=(l+r)>>1;
if (treel[t<<1]==mid-l+1) treel[t]+=treel[t<<1|1];
treer[t]=treer[t<<1|1];
if (treer[t<<1|1]==r-mid) treer[t]+=treer[t<<1];
}
void pushdown(int t,int l,int r)
{
if (tag[t]==-1) return;
int mid=(l+r)>>1;
if (tag[t]==0)
{
treel[t<<1]=treer[t<<1]=tree[t<<1]=mid-l+1;
tree[t<<1|1]=treel[t<<1|1]=treer[t<<1|1]=r-mid;
tag[t<<1]=tag[t<<1|1]=tag[t];
}
else
{
treel[t<<1]=treer[t<<1]=tree[t<<1]=0;
tree[t<<1|1]=treer[t<<1|1]=treel[t<<1|1]=0;
tag[t<<1]=tag[t<<1|1]=tag[t];
}
tag[t]=-1;
}
void build(int l,int r,int t)
{
if (l==r)
{
tree[t]=treel[t]=treer[t]=1;
tag[t]=-1;
return;
}
int mid=(l+r)>>1;
build(l,mid,t<<1);
build(mid+1,r,t<<1|1);
update(t,l,r);
tag[t]=-1;
}
int query(int l,int r,int key,int t)
{
if (l==r) return l;
pushdown(t,l,r);
int mid=(l+r)>>1;
if (tree[t<<1]>=key) return query(l,mid,key,t<<1);
else if (treer[t<<1]+treel[t<<1|1]>=key) return mid-treer[t<<1]+1;
else return query(mid+1,r,key,t<<1|1);
}
void modify(int l,int r,int x,int y,int key,int t)
{
if (l==x&&y==r)
{
tag[t]=key;
if (key) treel[t]=treer[t]=tree[t]=0;
else treel[t]=treer[t]=tree[t]=r-l+1;
return;
}
pushdown(t,l,r);
int mid=(l+r)>>1;
if (y<=mid) modify(l,mid,x,y,key,t<<1);
else if (x>mid) modify(mid+1,r,x,y,key,t<<1|1);
else modify(l,mid,x,mid,key,t<<1),modify(mid+1,r,mid+1,y,key,t<<1|1);
update(t,l,r);
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
build(1,n,1);
int l,r;
while (m--)
{
int k;
scanf("%d",&k);
if (k==1)
{
scanf("%d",&l);
if (tree[1]>=l)
{
int ans=query(1,n,l,1);
printf("%d\n",ans);
modify(1,n,ans,ans+l-1,1,1);
}
else puts("0");
}
else
{
scanf("%d%d",&l,&r);
modify(1,n,l,l+r-1,0,1);
}
}
return 0;
}