POJ 3667 Hotel(线段树区间合并)
Posted overrate-wsj
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 3667 Hotel(线段树区间合并)相关的知识,希望对你有一定的参考价值。
题意:
[1,N]区间内开始为空,有两种操作1) 1 a 找到长度为a的区间,并且尽量开头靠左,返回最左的位置并check in. 2) 2 a b 将[a,b-1]区间check out.
思路:
线段树-区间合并,对于每个节点记录三个值.1).lsum表示该节点区间从左边开始的空的区间长度2).rsum表示该节点区间从右到左开始空的区间长度3).sum表示该节点区间最长的空的区间长度
进行push_down的操作的时候,对于laz标记,看该区间是何标记,并将其两个子区间标记为相应值,对于push_up操作.更新其节点的三个值
lsum[rt] 置为左儿子的lsum值.如果左儿子该区间的lsum就是左儿子的区间长度,那么就可以加上右儿子的lsum值了
rsum[rt] 置为右儿子的rsum值.如果右儿子该区间的rsum就是右儿子的区间长度,那么就可以加上左儿子的rsum值了
sum[rt] 是左儿子的sum的值,右儿子的sum的值,中间一段sum的值的最大取值.
#include<iostream> #include<algorithm> #include<cstdio> #define ls (rt<<1) #define rs (rt<<1|1) using namespace std; const int maxn=5e4+10; struct node{ int lsum,rsum,sum,cover; }hotel[maxn<<2]; struct Segment_Tree{ void pushUp(int rt,int m) { hotel[rt].lsum=hotel[ls].lsum; hotel[rt].rsum=hotel[rs].rsum; if(hotel[rt].lsum==m-(m>>1)) hotel[rt].lsum+=hotel[rs].lsum; if(hotel[rt].rsum==(m>>1)) hotel[rt].rsum+=hotel[ls].rsum; hotel[rt].sum=max(hotel[ls].rsum+hotel[rs].lsum,max(hotel[ls].sum,hotel[rs].sum)); } void pushDown(int rt,int len) { if(hotel[rt].cover!=-1){ hotel[rs].cover=hotel[ls].cover=hotel[rt].cover; hotel[ls].lsum=hotel[ls].rsum=hotel[ls].sum=hotel[ls].cover?0:len-(len>>1); hotel[rs].lsum=hotel[rs].rsum=hotel[rs].sum=hotel[rs].cover?0:(len>>1); hotel[rt].cover=-1; } } void build(int l,int r,int rt) { hotel[rt].lsum=hotel[rt].rsum=hotel[rt].sum=r-l+1; hotel[rt].cover=-1; if(l==r) return; int mid=(l+r)>>1; build(l,mid,ls); build(mid+1,r,rs); } void update(int L,int R,int C,int l,int r,int rt) { if(L<=l&&r<=R){ hotel[rt].cover=C; hotel[rt].sum=hotel[rt].lsum=hotel[rt].rsum=hotel[rt].cover?0:r-l+1; return; } int m=(l+r)>>1; pushDown(rt,r-l+1); if(L<=m) update(L,R,C,l,m,ls); if(R>m) update(L,R,C,m+1,r,rs); pushUp(rt,r-l+1); } int query(int w,int l,int r,int rt) { if(l==r) return l; pushDown(rt,r-l+1); int mid=(l+r)>>1; if(hotel[ls].sum>=w) return query(w,l,mid,ls); else if(hotel[ls].rsum+hotel[rs].lsum>=w) return mid-hotel[ls].rsum+1; return query(w,mid+1,r,rs); } }T; int main() { int n,k,op,len,s; while(scanf("%d%d",&n,&k)!=EOF){ T.build(1,n,1); for(int i=1;i<=k;i++){ scanf("%d",&op); if(op==1){ scanf("%d",&len); if(hotel[1].sum<len){ cout<<0<<endl; continue; } s=T.query(len,1,n,1); cout<<s<<endl; T.update(s,s+len-1,1,1,n,1); } else{ scanf("%d%d",&s,&len); T.update(s,s+len-1,0,1,n,1); } } } return 0; }
以上是关于POJ 3667 Hotel(线段树区间合并)的主要内容,如果未能解决你的问题,请参考以下文章