线段树——讲课用——最长连续空位
题目链接:https://www.luogu.org/problemnew/show/P2894
题意:
酒店n个房间,m个操作:入住或退房
如果操作为入住,同一批客人安排的房间号必须连续
操作1:有x个客人要入住,输出满足条件的最小的房间编号,若不满足条件输出0
操作2:房间为[x,y]的客人要退房
题解:
如果你会了第一题(BSS),这题就简单了
题意转化:询问最长连续空位位置,带修改
如果没有操作2,把每个房间权值看成1,就变成了BSS问题,不过输出的是左端点位置
操作2仅是一个区间修改罢了
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define N 50000 int n,m; int mx[N<<2|1],lmx[N<<2|1],rmx[N<<2|1]; int f[N<<2|1],siz[N<<2|1]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void build(int k,int l,int r) { siz[k]=mx[k]=lmx[k]=rmx[k]=r-l+1; f[k]=-1; if(l==r) return; int mid=l+r>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); } void down(int k,int l,int r) { int L=k<<1,R=k<<1|1; if(f[k]) mx[L]=lmx[L]=rmx[L]=mx[R]=lmx[R]=rmx[R]=0; else { mx[L]=lmx[L]=rmx[L]=siz[L]; mx[R]=lmx[R]=rmx[R]=siz[R]; } f[L]=f[R]=f[k]; f[k]=-1; } int query(int k,int l,int r,int len) { if(l==r) return l; if(f[k]!=-1) down(k,l,r); int mid=l+r>>1; if(mx[k<<1]>=len) return query(k<<1,l,mid,len); if(rmx[k<<1]+lmx[k<<1|1]>=len) return mid-rmx[k<<1]+1; return query(k<<1|1,mid+1,r,len); } void up(int k) { int L=k<<1,R=k<<1|1; mx[k]=max(mx[L],mx[R]); mx[k]=max(mx[k],rmx[L]+lmx[R]); if(mx[L]==siz[L]) lmx[k]=mx[L]+lmx[R]; else lmx[k]=lmx[L]; if(mx[R]==siz[R]) rmx[k]=mx[R]+rmx[L]; else rmx[k]=rmx[R]; } void change(int k,int l,int r,int opl,int opr,int in) { if(l>=opl && r<=opr) { f[k]=in; if(!in) mx[k]=lmx[k]=rmx[k]=r-l+1; else mx[k]=lmx[k]=rmx[k]=0; return; } if(f[k]!=-1) down(k,l,r); int mid=l+r>>1; if(opl<=mid) change(k<<1,l,mid,opl,opr,in); if(opr>mid) change(k<<1|1,mid+1,r,opl,opr,in); up(k); } void init() { read(n); read(m); build(1,1,n); int opt,x,y; while(m--) { read(opt); if(opt==1) { read(x); if(mx[1]<x) printf("0\n"); else { y=query(1,1,n,x); printf("%d\n",y); change(1,1,n,y,y+x-1,1); } } else { read(x); read(y); change(1,1,n,x,x+y-1,0); } } } int main() { init(); return 0; }