P2894 [USACO08FEB]Hotel G
用维护区间最长连续1的方法就可以维护
但是还要维护一下最左边,不过这问题不大
维护一个区间最长连续子段,不在意位置就可以了
然后就可以在查询的时候,先看一看在不在左边,在看一看在不在中间,最后看一看在不在右边
就解决了
可见学线段树靠背模板是不行的
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#define lll long long
using namespace std;
int n,m;
int x,y;
struct t{
int lm;
int rm;
int sum;
int l;
int lazy;
}tr[500000];
// f=1入住
void pushdown(int ro){
if(tr[ro].lazy==1){
tr[ro<<1].lm=tr[ro<<1].rm=tr[ro<<1].sum=0;
tr[ro<<1].lazy=1;
tr[ro<<1|1].lm=tr[ro<<1|1].rm=tr[ro<<1|1].sum=0;
tr[ro<<1|1].lazy=1;
tr[ro].lazy=0;
}
if(tr[ro].lazy==2){
tr[ro<<1].lm=tr[ro<<1].rm=tr[ro<<1].sum=tr[ro<<1].l;
tr[ro<<1].lazy=2;
tr[ro<<1|1].lm=tr[ro<<1|1].rm=tr[ro<<1|1].sum=tr[ro<<1|1].l;
tr[ro<<1|1].lazy=2;
tr[ro].lazy=0;
}
}
void pushup(int ro){
tr[ro].sum=max(tr[ro<<1].sum,max(tr[ro<<1|1].sum,tr[ro<<1].rm+tr[ro<<1|1].lm));
tr[ro].lm=tr[ro<<1].sum==tr[ro<<1].l?tr[ro<<1].sum+tr[ro<<1|1].lm:tr[ro<<1].lm;
tr[ro].rm=tr[ro<<1|1].sum==tr[ro<<1|1].l?tr[ro<<1|1].sum+tr[ro<<1].rm:tr[ro<<1|1].rm;
}
void add(int ro,int l,int r,int L,int R,int f){
if(L<=l&&r<=R){
if(f==1){
tr[ro].lm=tr[ro].rm=tr[ro].sum=0;
tr[ro].lazy=1;
}else{
tr[ro].lm=tr[ro].rm=tr[ro].sum=tr[ro].l;
tr[ro].lazy=2;
}
return ;
}
pushdown(ro);
int mid=(l+r)>>1;
if(L<=mid) add(ro<<1,l,mid,L,R,f);
if(R>mid) add(ro<<1|1,mid+1,r,L,R,f);
pushup(ro);
}
int que(int ro,int l,int r){
if(l==r) return l;
pushdown(ro);
int mid=(l+r)>>1;
if(tr[ro<<1].sum>=y){
return que(ro<<1,l,mid);
}else
if(tr[ro<<1].rm+tr[ro<<1|1].lm>=y){
return mid-tr[ro<<1].rm+1;
}
else{
return que(ro<<1|1,mid+1,r);
}
}
void ini(int ro,int l,int r){
if(l==r){
tr[ro].l=1;
return ;
}
int mid=(l+r)>>1;
tr[ro].l=(r-l+1);
ini(ro<<1,l,mid);
ini(ro<<1|1,mid+1,r);
}
int z;
int main(){
scanf("%d%d",&n,&m);
ini(1,1,n);
add(1,1,n,1,n,2);
while(m--){
scanf("%d%d",&x,&y);
if(x==1){
if(tr[1].sum>=y){
int l=que(1,1,n);
cout<<l<<endl;
add(1,1,n,l,l+y-1,1);
}else{
cout<<0<<endl;
}
}else{
scanf("%d",&z);
add(1,1,n,y,y+z-1,2);
}
}
return 0;
}