传送门
题目大意:
某个闻名中外的旅店有n个房间(由于很著名,所以n<=5W),现在有m个旅客提出了要求,1 x代表这位旅客要预定x个连续的房间,并且编号越靠前越好,2 x y代表这位旅客要退x~x+y-1这一段连续的房间…
对于每次预定操作,输出第一个房间的编号,如果无法满足,输出0
分析:
(队长曾经说过…)我们先把题意简单化:
有一段1~n的区间,初始值为1,现在有m次操作,分为两种:
1、找到最靠前的长度为x的一段连续的1区间,并且把这段区间变为0…
2、把x~y这段0区间变为1…
简单来说,这道题就是一个区间修改,区间查询的题目,肯定需要数据结构,应该使用什么捏?
线段树…
记得某位神犇在博客里写道:做线段树不能为了做题而做,首先线段树是一种辅助结构,它是为问题而生的,因而必须具体问题具体分析…..
好有哲理的一段话说….>_<
写线段树,最重要的是要确定好线段树需要记录那些节点信息…
好了,不扯了,我们还是回归此题吧>_<…
这道题的修改操作就是最简单的修改操作,那么查询操作怎么办捏??
既然我们要查询的和区间长度有关系,那么我们的节点信息肯定也是区间长度…
话说我们一定至少需要3个信息:
1、midlen,就是区间内连续最长的一段1的长度
2、llen最长前缀1区间
3、rlen最长后缀1区间
话说2&3是干什么的(打酱油的>_<)
因为我们如果要维护midlen,那么llen&rlen是必不可少滴~~
接下来还有一个麻烦事—要求查询区间最靠前
(⊙o⊙)…
分类讨论吧…
1、如果左儿子的midlen>=x那么就返回query(左儿子)
2、如果左儿子的后缀+右儿子的前缀>=x,直接返回左儿子的后缀开始的下标
3、若果右儿子的midlen>=x那么就返回query(右儿子)
4、那就只能返回0了(忧桑~~>_<)
话说,线段树每次都虐我,而且每次写线段树基本都需要好几个小时,<( ̄3 ̄)>… 忧桑啊… ̄へ ̄
代码如下:
(模板copyMG)
#include
#include
#include
#include
using namespace std;
const int maxn=50000+5;
int n,m;
struct lala{
int l,r,llen,rlen,midlen,lazy;//lazy=1全满,lazy=0全空,lazy=-1...自己体会吧
void changelen(){
midlen=llen=rlen=lazy*(r-l+1);
}
}tree[maxn*4];
inline void build(int tr,int l,int r){
tree[tr].l=l,tree[tr].r=r,tree[tr].lazy=1;
tree[tr].changelen();
if(l==r)
return;
int mid=(tree[tr].r+tree[tr].l)>>1;
build(tr<<1,l,mid),build(tr<<1|1,mid+1,r);
}
inline void change(int tr,int l,int r,int val){
if(tree[tr].l==l&&tree[tr].r==r){
tree[tr].lazy=val,tree[tr].changelen();
return;
}
int mid=(tree[tr].l+tree[tr].r)>>1;
if(tree[tr].lazy!=-1){
tree[tr<<1].lazy=tree[tr<<1|1].lazy=tree[tr].lazy;
tree[tr].lazy=-1;
tree[tr<<1].changelen(),tree[tr<<1|1].changelen();
}
if(l>mid)
change(tr<<1|1,l,r,val);
else if(r<=mid)
change(tr<<1,l,r,val);
else
change(tr<<1,l,mid,val),change(tr<<1|1,mid+1,r,val);
int tmp=max(tree[tr<<1].midlen,tree[tr<<1|1].midlen);
tree[tr].midlen=max(tmp,tree[tr<<1].rlen+tree[tr<<1|1].llen);
tree[tr].llen=tree[tr<<1].llen,tree[tr].rlen=tree[tr<<1|1].rlen;
if(tree[tr<<1].midlen==tree[tr<<1].r-tree[tr<<1].l+1)
tree[tr].llen+=tree[tr<<1|1].llen;
if(tree[tr<<1|1].midlen==tree[tr<<1|1].r-tree[tr<<1|1].l+1)
tree[tr].rlen+=tree[tr<<1].rlen;
}
inline int query(int tr,int len){
if(tree[tr].l==tree[tr].r&&len==1)
return tree[tr].l;
if(tree[tr].lazy!=-1){
tree[tr<<1].lazy=tree[tr<<1|1].lazy=tree[tr].lazy;
tree[tr].lazy=-1;
tree[tr<<1].changelen(),tree[tr<<1|1].changelen();
}
if(tree[tr<<1].midlen>=len)
return query(tr<<1,len);
if(tree[tr<<1].rlen+tree[tr<<1|1].llen>=len)
return tree[tr<<1].r-tree[tr<<1].rlen+1;
if(tree[tr<<1|1].midlen>=len)
return query(tr<<1|1,len);
return 0;
}
signed main(void){
scanf("%d%d",&n,&m),build(1,1,n);
while(m--){
int x,y,z;
scanf("%d",&z);
if(z==1){
scanf("%d",&x),cout<<(y=query(1,x))<if(y!=0)
change(1,y,y+x-1,0);
}
else
scanf("%d%d",&x,&y),change(1,x,x+y-1,1);
}
return 0;
}
by >_< neighthorn