线段树||BZOJ1593: [Usaco2008 Feb]Hotel 旅馆||Luogu P2894 [USACO08FEB]酒店Hotel
题解:和基础的线段树操作差别不是很大,就是在传统的线段树基础上多维护一段区间最长的合法前驱(h_),最长合法后驱(t_),一段中最长的合法区间(mx)。询问时由于查询的是最左边的合法端点,所以要从左到中间到右边依次考虑情况。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #define max(a,b) ((a)>(b)?(a):(b)) 5 using namespace std; 6 const int maxn=50000+5,maxm=50000+5; 7 int N,M,o,D,X,ans; 8 inline int rd(){ 9 int x=0;char c=getchar(); 10 while(c<'0'||c>'9')c=getchar(); 11 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 12 return x; 13 } 14 struct Tree{ 15 int l,r,lazy,h_,t_,mx; 16 }t[maxn<<2]; 17 inline void Pushup(int x){ 18 int ls=x<<1,rs=x<<1|1; 19 if(t[ls].r-t[ls].l+1==t[ls].mx)t[x].h_=t[ls].mx+t[rs].h_;else t[x].h_=t[ls].h_; 20 if(t[rs].r-t[rs].l+1==t[rs].mx)t[x].t_=t[rs].mx+t[ls].t_;else t[x].t_=t[rs].t_; 21 t[x].mx=max(t[ls].mx,t[rs].mx); 22 t[x].mx=max(t[x].mx,t[ls].t_+t[rs].h_); 23 return; 24 } 25 inline void Build(int x,int l,int r){ 26 t[x].l=l;t[x].r=r;t[x].lazy=-1; 27 if(l==r){ 28 t[x].h_=t[x].t_=t[x].mx=1; 29 return; 30 } 31 int mid=(l+r)>>1; 32 Build(x<<1,l,mid);Build(x<<1|1,mid+1,r); 33 Pushup(x); 34 return; 35 } 36 inline void Pushdown(int x){ 37 if(t[x].lazy>=0){ 38 int k=t[x].lazy,ls=x<<1,rs=x<<1|1;t[x].lazy=-1; 39 if(k==1){ 40 t[ls].h_=t[ls].t_=t[ls].mx=0; 41 t[rs].h_=t[rs].t_=t[rs].mx=0; 42 } 43 else{ 44 t[ls].h_=t[ls].t_=t[ls].mx=t[ls].r-t[ls].l+1; 45 t[rs].h_=t[rs].t_=t[rs].mx=t[rs].r-t[rs].l+1; 46 } 47 t[ls].lazy=t[rs].lazy=k; 48 } 49 return; 50 } 51 inline int Solve(int x,int d){ 52 int ls=x<<1,rs=x<<1|1,l=t[x].l,r=t[x].r; 53 if(r-l+1==t[x].mx&&t[x].mx==d)return l; 54 Pushdown(x); 55 if(t[ls].mx>=d)return Solve(ls,d); 56 if(t[ls].t_+t[rs].h_>=d)return (t[ls].r-t[ls].t_+1); 57 if(t[rs].mx>=d)return Solve(rs,d); 58 return 0; 59 } 60 inline void Update(int x,int ql,int qr,int o){ 61 int l=t[x].l,r=t[x].r; 62 if(ql<=l&&r<=qr){ 63 if(o==1)t[x].h_=t[x].t_=t[x].mx=0; 64 else t[x].h_=t[x].t_=t[x].mx=r-l+1; 65 t[x].lazy=o; 66 return; 67 } 68 int mid=(l+r)>>1,ls=x<<1,rs=x<<1|1; 69 Pushdown(x); 70 if(ql<=mid)Update(ls,ql,qr,o); 71 if(qr>mid)Update(rs,ql,qr,o); 72 Pushup(x); 73 return; 74 } 75 inline void write(int x){ 76 char a[12];int len=0; 77 for(;x;x/=10)a[len++]=x%10; 78 if(!len)putchar('0'); 79 else while(len)putchar(a[--len]+'0'); 80 putchar('\n'); 81 } 82 int main(){ 83 N=rd();M=rd(); 84 Build(1,1,N); 85 while(M--){ 86 o=rd(); 87 if(o==1){ 88 D=rd(); 89 ans=Solve(1,D); 90 write(ans); 91 if(ans)Update(1,ans,ans+D-1,1);//1表示有住人 92 } 93 else{ 94 X=rd();D=rd(); 95 Update(1,X,X+D-1,0); 96 } 97 } 98 return 0; 99 }
//我为了卡常加入了快速读入和快速输出,实际食用代码时完全可以无视。
By:AlenaNuna