线段树区间合并POJ3667-Hotel
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树区间合并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的主要内容,如果未能解决你的问题,请参考以下文章