poj3667 Hotel (线段树--区间合并)转自网络
2013-05-02 18:00
369 查看
题目大意:有一段长为n的线段,在这条线段上进行操作:1.找出最靠前的长度为l的空线段,并把一个长为l的线段插入在这个地方.2.删除从某点开始长为l的一段线段(有可能并不存在,总之就是把这个区间清空).输出每次插入操作的位置.
一个有 N 个连续房间的旅馆,对 m 次询问对应两种操作。
1 a 询问是不是有连续长度为a的空房间,有的话住进最左边
2 a b 将[a,a+b-1]的房间清空
分析: 区间合并类线段树。
update 成段更新
query 找到满足条件的最左端点
转自网络:http://blog.csdn.net/h2952220/article/details/7911622
因为注释很详尽 。。 要好好学习~
一个有 N 个连续房间的旅馆,对 m 次询问对应两种操作。
1 a 询问是不是有连续长度为a的空房间,有的话住进最左边
2 a b 将[a,a+b-1]的房间清空
分析: 区间合并类线段树。
update 成段更新
query 找到满足条件的最左端点
转自网络:http://blog.csdn.net/h2952220/article/details/7911622
因为注释很详尽 。。 要好好学习~
#include <iostream> #include <cstdio> #include <cstring> #define lson l,mid,dex<<1 /************************注意在下的宏定义......免得楼下出现神奇变量看不懂....*********/ #define rson mid+1,r,dex<<1|1 #define havemid int mid = (l+r)>>1 #define left (dex<<1) #define right (dex<<1|1) using namespace std; const int maxx = 51000; int tage[maxx<<2];//延迟标志,有3个值,-1表示无需更新,1表示有人入住需要把空房间数清零,0表示有人离开,需要把空房间数堆满 int rooml[maxx<<2];//该区间左端开始的空房间数目 int roomr[maxx<<2];//该区间右端开始的空房间数目 int roommid[maxx<<2];//该区间里<span style="color:#ff0000;">最长的</span>连续空房间的数目 void Push_down(int dex,int x) { if(tage[dex]!=-1) { tage[dex<<1] = tage[dex<<1|1] = tage[dex];//延迟标志向下传递,不解释 rooml[right] = roomr[right] = roommid[right] = tage[dex]?0:(x>>1);//如果延迟标志为0,则将区间内空房间数清零(详见楼上注解) rooml[left] = roomr[left] = roommid[left] = tage[dex]?0:(x-(x>>1));//如果延迟标志为1,则将区间内空房间数堆满 tage[dex] = -1;//表示本区间已经更新 } } void Push_up(int dex,int x) { rooml[dex] = rooml[left];//无论左端开始数的空房间数是否充满整个空间(即即使要加上右儿子从左端开始数的空房间数),都要先把左儿子的房间数复制给父亲的rooml roomr[dex] = roomr[right];//同上 if(rooml[left] == (x-(x>>1))) rooml[dex]+=rooml[right];//如果左儿子的rooml充满区间,则加上右儿子的rooml if(roomr[right] == (x>>1)) roomr[dex]+=roomr[left];//如果右儿子的roomr充满区间,则加上左儿子的roomr roommid[dex] = max(roomr[left] + rooml[right],max(roommid[left], roommid[right]));//roomr[left] + rooml[right]表示合并区间时产生的连续不断的空房间数 } void build(int l,int r,int dex)//不解释= = { tage[dex] = -1; rooml[dex] = roomr[dex] = roommid[dex] = r-l+1; if(l==r) return; havemid;//宏定义 build(lson);//宏定义+1 build(rson);//宏定义+2 } void updata(int L,int R,int mode, int l,int r,int dex) { if(L<=l && R>=r)//如果目前区间为搜索区间的子区间,则子区间被完全覆盖 { rooml[dex] = roomr[dex] = roommid[dex] = mode?0:r-l+1;//根据延迟标志选择性更新 tage[dex] = mode; return ; } Push_down(dex, r-l+1);//在楼下需要用到儿子节点的语句之前,先行一步向下更新(还没更新的)儿子节点 havemid; if(L<=mid) updata(L,R,mode,lson);//如果左儿子还有没更新的就更新 if(R>mid) updata(L,R,mode,rson);//略同上 Push_up(dex,r-l+1);//合并区间 } int query(int x,int l,int r,int dex) { if(l==r) return l;//搜到子节点则返回 (经测试,返回0竟然也没问题= =,估计数据不怎么样?) Push_down(dex,r-l+1);//更新未更新的儿子节点 havemid; if(roommid[left] >= x) return query(x,lson);//一直找左儿子的最大连续空房间,一直找到左儿子的roommid不满足,则这个区间一定落在中间的区间,否则在右区间 else if(rooml[dex<<1|1]+roomr[dex<<1]>=x) return mid - roomr[dex<<1]+1; else return query(x,rson); } int main()//不解释 { // freopen("123.txt","r",stdin); int n,m; while(~scanf("%d %d",&n,&m)) { build(1,n,1); for(int i=1; i<=m; i++) { int a; scanf("%d",&a); if(a==1) { int b; scanf("%d",&b); if(roommid[1]<b) puts("0"); else { int ans = query(b,1,n,1); printf("%d\n",ans); updata(ans,ans+b-1,1,1,n,1); } } else { int u,v; scanf("%d %d",&u,&v); updata(u,u+v-1,0,1,n,1); } } } return 0; }
相关文章推荐
- poj3667 Hotel (线段树--区间合并)转自网络【2】
- poj3667 Hotel (线段树区间合并)
- 【线段树区间合并】POJ3667-Hotel
- poj3667 hotel(线段树区间合并)
- [POJ3667]Hotel(线段树,区间合并)
- poj3667---Hotel 线段树区间合并,区间更新
- poj3667 Hotel 线段树延迟更新 区间合并
- [POJ3667]Hotel(线段树,区间合并,重写)
- [线段树]poj3667 Hotel(区间合并、更新、延迟/懒惰标记
- POJ3667:Hotel(线段树区间合并)
- POJ3667——线段树区间合并(未搞透)——Hotel
- poj3667 Hotel 线段树 区间合并
- POJ3667-Hotel-线段树区间合并(模板)
- poj3667-Hotel 线段树区间合并
- poj3667 Hotel (线段树+区间合并)
- POJ 3667 Hotel ( 线段树区间合并 )
- poj 3667 Hotel(线段树,成段更新,区间合并,Lazy思想)
- POJ 3667 Hotel 区间合并+线段树 *
- POJ 3667 hotel 线段树区间合并
- POJ 3667 Hotel 线段树 区间合并 入门题