【线段树区间合并】POJ3667-Hotel

【题意】

一段区间初始均为可行。有两个操作:

1→找出长度为w的一段可行区间,如果存在则返回这个可行区间最靠左的情况,并将该区间设为不可行;

2→将区间[a,b]设为可行区间。

【思路】

经典的线段树合并,代码依旧用的是神犇的线段树模板。详见注释。

【错误点】

延迟标记的时候,忘记把cover清为-1了,导致RE!

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cstdlib>
  6 using namespace std;
  7 #define lson l,m,rt<<1
  8 #define rson m+1,r,rt<<1|1 
  9 const int MAXN=55555+10;
 10 int cover[MAXN<<2];//-1表示当前没有覆盖标记,1表示均覆盖为不可行,0表示均覆盖为可行 
 11 int lsum[MAXN<<2];//该区间从左起连续的可用区间长度的最大值 
 12 int msum[MAXN<<2];//该区间中连续的可用区间长度的最大值 
 13 int rsum[MAXN<<2];//该区间从右起连续的可用区间长度的最大值 
 14 
 15 void PushUp(int rt,int m)
 16 {
 17     lsum[rt]=lsum[rt<<1];
 18     if (lsum[rt]==m-(m>>1)) lsum[rt]+=lsum[rt<<1|1];
 19     /*如果左孩子全部为可用区间,那么加上右孩子的左端*/
 20     rsum[rt]=rsum[rt<<1|1];
 21     if (rsum[rt]==m>>1) rsum[rt]+=rsum[rt<<1];
 22     /*同上*/
 23     msum[rt]=max(max(msum[rt<<1],msum[rt<<1|1]) , rsum[rt<<1]+lsum[rt<<1|1]);
 24     /*该区间的可用区间可能是:左孩子最大的可用区间、有孩子最大的可用区间,和跨越左右孩子加在一起的可用区间*/
 25 }
 26 
 27 void PushDown(int rt,int m) 
 28 {
 29     if (cover[rt]!=-1)
 30     {
 31         cover[rt<<1]=cover[rt<<1|1]=cover[rt];
 32         if (cover[rt]==1)
 33         {
 34             msum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=0;
 35             msum[rt<<1|1]=lsum[rt<<1|1]=rsum[rt<<1|1]=0;
 36         }
 37         else
 38         {
 39             msum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=m-(m>>1);
 40             msum[rt<<1|1]=lsum[rt<<1|1]=rsum[rt<<1|1]=m>>1;
 41         }
 42         cover[rt]=-1;
 43         /*千万不要忘记将rt清为-1*/ 
 44     }
 45 }
 46 
 47 
 48 int query(int w,int l,int r,int rt)
 49 {
 50     if (l==r) return l;
 51     PushDown(rt,r-l+1);
 52     int m=(l+r)>>1;
 53     if (msum[rt<<1]>=w) return(query(w,lson));
 54     /*由于要找最左边的区间,按照左孩子、跨越两者、有孩子的顺序查找*/
 55     if (rsum[rt<<1]+lsum[rt<<1|1]>=w) return(m-rsum[rt<<1]+1);
 56     return(query(w,rson));
 57 }
 58 
 59 void update(int L,int R,int o,int l,int r,int rt)
 60 {
 61     if (L<=l && r<=R)
 62     {
 63         cover[rt]=o;
 64         if (o==1) msum[rt]=lsum[rt]=rsum[rt]=0;
 65             else msum[rt]=lsum[rt]=rsum[rt]=r-l+1;
 66         return;
 67     }
 68     PushDown(rt,r-l+1);//这里是l和r,不要写成L和R 
 69     int m=(l+r)>>1;
 70     if (L<=m) update(L,R,o,lson); 
 71     if (m<R)  update(L,R,o,rson);
 72     PushUp(rt,r-l+1);
 73 }
 74 
 75 void build(int l,int r,int rt)
 76 {
 77     msum[rt]=lsum[rt]=rsum[rt]=r-l+1;
 78     cover[rt]=-1;
 79     if (l==r) return;
 80     int m=(l+r)>>1;
 81     build(lson);
 82     build(rson);
 83 }
 84 
 85 int main()
 86 {
 87     int n,m;
 88     scanf("%d%d",&n,&m);
 89     build(1,n,1);
 90     for (int i=0;i<m;i++)
 91     {
 92         int op;
 93         scanf("%d",&op);
 94         if (op==1)
 95         {
 96             int w;
 97             scanf("%d",&w);
 98             if (msum[1]<w) cout<<0<<endl;
 99             /*如果根的可用区间已经小于w,那么一定是找不到长度为w的可用区间*/
100                 else
101                 {
102                       int p=query(w,1,n,1);
103                       cout<<p<<endl;
104                       update(p,p+w-1,1,1,n,1);
105                 }
106         }
107         else
108         {
109             int u,v;
110             scanf("%d%d",&u,&v);
111             update(u,u+v-1,0,1,n,1);
112         }
113     }
114     return 0;
115 }

 

你可能感兴趣的:(【线段树区间合并】POJ3667-Hotel)