【线段树区间合并】POJ3667-Hotel
2016-01-31 09:55
316 查看
【题意】
一段区间初始均为可行。有两个操作:
1→找出长度为w的一段可行区间,如果存在则返回这个可行区间最靠左的情况,并将该区间设为不可行;
2→将区间[a,b]设为可行区间。
【思路】
经典的线段树合并,代码依旧用的是神犇的线段树模板。详见注释。
【错误点】
延迟标记的时候,忘记把cover清为-1了,导致RE!
一段区间初始均为可行。有两个操作:
1→找出长度为w的一段可行区间,如果存在则返回这个可行区间最靠左的情况,并将该区间设为不可行;
2→将区间[a,b]设为可行区间。
【思路】
经典的线段树合并,代码依旧用的是神犇的线段树模板。详见注释。
【错误点】
延迟标记的时候,忘记把cover清为-1了,导致RE!
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int MAXN=55555+10; int cover[MAXN<<2];//-1表示当前没有覆盖标记,1表示均覆盖为不可行,0表示均覆盖为可行 int lsum[MAXN<<2];//该区间从左起连续的可用区间长度的最大值 int msum[MAXN<<2];//该区间中连续的可用区间长度的最大值 int rsum[MAXN<<2];//该区间从右起连续的可用区间长度的最大值 void PushUp(int rt,int m) { lsum[rt]=lsum[rt<<1]; if (lsum[rt]==m-(m>>1)) lsum[rt]+=lsum[rt<<1|1]; /*如果左孩子全部为可用区间,那么加上右孩子的左端*/ rsum[rt]=rsum[rt<<1|1]; if (rsum[rt]==m>>1) rsum[rt]+=rsum[rt<<1]; /*同上*/ msum[rt]=max(max(msum[rt<<1],msum[rt<<1|1]) , rsum[rt<<1]+lsum[rt<<1|1]); /*该区间的可用区间可能是:左孩子最大的可用区间、有孩子最大的可用区间,和跨越左右孩子加在一起的可用区间*/ } void PushDown(int rt,int m) { if (cover[rt]!=-1) { cover[rt<<1]=cover[rt<<1|1]=cover[rt]; if (cover[rt]==1) { msum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=0; msum[rt<<1|1]=lsum[rt<<1|1]=rsum[rt<<1|1]=0; } else { msum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=m-(m>>1); msum[rt<<1|1]=lsum[rt<<1|1]=rsum[rt<<1|1]=m>>1; } cover[rt]=-1; /*千万不要忘记将rt清为-1*/ } } int query(int w,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]>=w) return(query(w,lson)); /*由于要找最左边的区间,按照左孩子、跨越两者、有孩子的顺序查找*/ if (rsum[rt<<1]+lsum[rt<<1|1]>=w) return(m-rsum[rt<<1]+1); return(query(w,rson)); } void update(int L,int R,int o,int l,int r,int rt) { if (L<=l && r<=R) { cover[rt]=o; if (o==1) msum[rt]=lsum[rt]=rsum[rt]=0; else msum[rt]=lsum[rt]=rsum[rt]=r-l+1; return; } PushDown(rt,r-l+1);//这里是l和r,不要写成L和R int m=(l+r)>>1; if (L<=m) update(L,R,o,lson); if (m<R) update(L,R,o,rson); PushUp(rt,r-l+1); } void build(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; build(lson); build(rson); } int main() { int n,m; scanf("%d%d",&n,&m); build(1,n,1); for (int i=0;i<m;i++) { int op; scanf("%d",&op); if (op==1) { int w; scanf("%d",&w); if (msum[1]<w) cout<<0<<endl; /*如果根的可用区间已经小于w,那么一定是找不到长度为w的可用区间*/ else { int p=query(w,1,n,1); cout<<p<<endl; update(p,p+w-1,1,1,n,1); } } else { int u,v; scanf("%d%d",&u,&v); update(u,u+v-1,0,1,n,1); } } return 0; }
相关文章推荐
- linux状态及原理全剖析
- 记录一下编译 打包 工具 Jenkins
- 大型网站架构系列
- CocoaPods下载并使用插件
- poj 1006(中国剩余定理)
- 日经春秋 20160131
- 弹出自适应图片大小的窗口弹出窗口根据图片大小,自动判断高和宽
- 安卓图片处理Picasso的解析使用
- hdu3038How Many Answers Are Wrong(并查集)
- 天声人語 20160131 1月の言葉から
- 网络工具类
- 固定内存块尺寸的内存池原理及代码
- c++读取文件目录
- PHP常量详解:define和const的区别
- Android-内存优化-Overdraw-多度绘制
- SCI简介
- Xutls3的使用
- JS获取图片实际宽高及根据图片大小进行自适应
- three.js 源代码凝视(十四)Math/Sphere.js
- Hibernate关联映射(转载)