题目链接:传送门
参考文章:传送门
思路:线段树区间合并问题,每次查询到满足线段树的区间最左值,然后更新线段树。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = ;
int lsum[maxn<<],rsum[maxn<<],msum[maxn<<],cover[maxn<<];
void build(int x,int l,int r)
{
lsum[x]=rsum[x]=msum[x]=r-l+;
if(l==r) return ;
int mid=(l+r)>>;
build(x<<,l,mid);
build(x<<|,mid+,r);
}
int MAX(int x,int y)
{
return x>y?x:y;
}
void pushup(int x,int k)
{
lsum[x]=lsum[x<<];
rsum[x]=rsum[x<<|];
msum[x]=MAX(MAX(msum[x<<],msum[x<<|]),lsum[x<<|]+rsum[x<<]);
if(lsum[x<<]==(k-(k>>))) lsum[x]+=lsum[x<<|];
if(rsum[x<<|]==k>>) rsum[x]+=rsum[x<<];
}
void pushdown(int x,int k)
{
if(cover[x]!=-)
{
cover[x<<]=cover[x<<|]=cover[x];
lsum[x<<]=rsum[x<<]=msum[x<<]=cover[x]?:(k-(k>>));
lsum[x<<|]=rsum[x<<|]=msum[x<<|]=cover[x]?:(k>>);
cover[x]=-;
}
}
void update(int x,int l,int r,int A,int B,int Item)
{
if(A<=l&&r<=B)
{
cover[x]=Item;
lsum[x]=rsum[x]=msum[x]=Item?:r-l+;
return ;
}
pushdown(x,r-l+);
int mid=(l+r)>>;
if(A<=mid) update(x<<,l,mid,A,B,Item);
if(B>mid) update(x<<|,mid+,r,A,B,Item);
pushup(x,r-l+);
}
int query(int x,int l,int r,int len)
{
if(l==r) return ;
pushdown(x,r-l+);
int mid=(l+r)>>;
if(msum[x<<]>=len) return query(x<<,l,mid,len);
else if(rsum[x<<]+lsum[x<<|]>=len) return mid-rsum[x<<]+;
else return query(x<<|,mid+,r,len);
}
int main(void)
{
int n,m,i,x,y,z;
while(~scanf("%d%d",&n,&m))
{
build(,,n);
while(m--)
{
scanf("%d",&x);
if(x==)
{
scanf("%d",&y);
if(msum[]<y)
{
printf("0\n");
continue;
}
z=query(,,n,y);
printf("%d\n",z);
update(,,n,z,z+y-,);
}
else
{
scanf("%d%d",&y,&z);
update(,,n,y,y+z-,);
}
}
}
return ;
}
http://poj.org/problem?id=3667