P2894 [USACO08FEB]Hotel G
阿新 • • 發佈:2021-10-05
用維護區間最長連續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; }