- 线段树维护的信息很简单,关键在于怎样通过这些信息设计查询函数回答题目的询问。对于每一个区间,如果它的左儿子的msum值大于等于x,则到左儿子里去找;如果左儿子的rsum加上右儿子的lsum大于等于x,则直接返回左儿子的右端点减去左儿子的rsum值;否则到右儿子里去找
#include <bits/stdc++.h>
using namespace std;
struct t1
{
int l,r,lsum,rsum,msum,bj;
#define len(x) t[x].r-t[x].l+1
}t[200005];
void build(int p,int l,int r)
{
t[p].l=l;
t[p].r=r;
t[p].lsum=t[p].rsum=t[p].msum=r-l+1;
t[p].bj=-1;
if(l==r)
{
return;
}
int mid=(l+r)>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
}
void spread(int p)
{
if(t[p].bj!=-1)
{
t[p*2].bj=t[p*2+1].bj=t[p].bj;
if(t[p].bj==0)
{
t[p*2].lsum=t[p*2].rsum=t[p*2].msum=len(p*2);
t[p*2+1].lsum=t[p*2+1].rsum=t[p*2+1].msum=len(p*2+1);
}
else
{
t[p*2].lsum=t[p*2].rsum=t[p*2].msum=0;
t[p*2+1].lsum=t[p*2+1].rsum=t[p*2+1].msum=0;
}
t[p].bj=-1;
}
}
void change(int p,int l,int r,int v)
{
if(l<=t[p].l&&r>=t[p].r)
{
if(v==0)
{
t[p].lsum=t[p].rsum=t[p].msum=len(p);
}
else
{
t[p].lsum=t[p].rsum=t[p].msum=0;
}
t[p].bj=v;
return;
}
spread(p);
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid)
{
change(p*2,l,r,v);
}
if(r>mid)
{
change(p*2+1,l,r,v);
}
t[p].lsum=t[p*2].lsum;
if(t[p*2].lsum==len(p*2))
{
t[p].lsum+=t[p*2+1].lsum;
}
t[p].rsum=t[p*2+1].rsum;
if(t[p*2+1].rsum==len(p*2+1))
{
t[p].rsum+=t[p*2].rsum;
}
t[p].msum=max(max(t[p*2].msum,t[p*2+1].msum),t[p*2].rsum+t[p*2+1].lsum);
}
int ask(int p,int x)
{
spread(p);
if(t[p*2].msum>=x)
{
return ask(p*2,x);
}
else if(t[p*2].rsum+t[p*2+1].lsum>=x)
{
return t[p*2].r-t[p*2].rsum+1;
}
else
{
return ask(p*2+1,x);
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;
cin>>n>>m;
build(1,1,n);
for(int i=1;i<=m;i++)
{
int opt,x,y;
cin>>opt>>x;
if(opt==1)
{
if(t[1].msum<x)
{
cout<<"0\n";
}
else
{
y=ask(1,x);
cout<<y<<"\n";
change(1,y,y+x-1,1);
}
}
else
{
cin>>y;
change(1,x,x+y-1,0);
}
}
return 0;
}