POJ 3667 Hotel
题意: 一个有 N 个连续房间的旅馆,对 m 次询问对应两种操作。
1 a 询问是不是有连续长度为a的空房间,有的话住进最左边
2 a b 将[a,a+b-1]的房间清空
分析: 区间合并类线段树。
update 成段更新
query 找到满足条件的最左端点
#include<stdio.h> #include<string.h> #define maxn 50005 int max(int a,int b) { return a>b?a:b; } int lsum[maxn<<2]; int rsum[maxn<<2]; int msum[maxn<<2]; int cover[maxn<<2]; void creat(int l,int r,int rt) { msum[rt]=lsum[rt]=rsum[rt]=r-l+1; cover[rt]=-1; if(l==r) return; int m=(l+r)>>1; creat(l,m,rt<<1); creat(m+1,r,rt<<1|1); } void pushup(int rt,int x) { lsum[rt]=lsum[rt<<1]; rsum[rt]=rsum[rt<<1|1]; if(lsum[rt]==x-(x>>1)) lsum[rt]+=lsum[rt<<1|1]; if(rsum[rt]==(x>>1)) rsum[rt]+=rsum[rt<<1]; msum[rt]=max(lsum[rt<<1|1]+rsum[rt<<1],max(msum[rt<<1],msum[rt<<1|1])); } void pushdown(int rt,int x) { if(cover[rt]!=-1) { cover[rt<<1]=cover[rt<<1|1]=cover[rt]; msum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=cover[rt]?0:x-(x>>1); msum[rt<<1|1]=lsum[rt<<1|1]=rsum[rt<<1|1]=cover[rt]?0:(x>>1); cover[rt]=-1; } } void update(int L,int R,int x,int l,int r,int rt) { if(L<=l&&r<=R) { msum[rt]=lsum[rt]=rsum[rt]=(r-l+1)*x; cover[rt]=x?0:1; return; } // 成段更新 pushdown(rt,r-l+1); int m=(l+r)>>1; if(L<=m) update(L,R,x,l,m,rt<<1); if(R>m) update(L,R,x,m+1,r,rt<<1|1); pushup(rt,r-l+1); } int query(int x,int l,int r,int rt) { if(l==r) return l; pushdown(rt,r-l+1); int m=(l+r)>>1; if(msum[rt<<1]>=x) return query(x,l,m,rt<<1); else if(rsum[rt<<1]+lsum[rt<<1|1]>=x) return m-rsum[rt<<1]+1; return query(x,m+1,r,rt<<1|1); } int main() { int a,b,p,n,m,k; scanf("%d%d",&n,&m); creat(1,n,1); while(m--) { scanf("%d",&p); if(p==1) { scanf("%d",&a); if(msum[1]<a) printf("0\n"); else { k=query(a,1,n,1); printf("%d\n",k); update(k,k+a-1,0,1,n,1); } } else { scanf("%d%d",&a,&b); update(a,a+b-1,1,1,n,1); } } return 0; }