POJ 3667 Hotel (初遇线段树区间合并)

来源:互联网 发布:php 大文件分片上传 编辑:程序博客网 时间:2024/06/13 08:54

题意:

有一个线段,从1到n,下面m个操作,操作分两个类型,以1开头的是查询操作,以2开头的是更新操作

1 w 表示在总区间内查询一个长度为w的可用区间并且要最靠左,能找到的话返回这个区间的左端点并占用了这个区间,找不到返回0 

2 a len , 表示从单位a开始,清除一段长度为len的区间(将其变为可用,不被占用),不需要输出。

思路:

这是第一次遇到线段树区间合并的题目,写下感悟,还是对线段的更新和查询工作,但是查询的对象的性质已经不像单点那样,查询的是某个线段的最大可用区间是多少,还要一并查询出最大可用区间最左端的位置,显然不能直接记录最左边的位置,因为父亲和儿子没有递推关系,所以要开其他的线段树记录其他的量,每次查询最起码要在O(1)的时间内算出最大可用区间的最左端位置。

而且也不能光记录最大可用间的长度是多少,因为这样父亲和儿子也构不成递推关系。所以要记录开其他的线段树,这是这类区间合并的共同问题,下面直接说解法方法:

可以开三棵线段树,一个记录此区间的最大可用区间的长度,一个记录此区间从左边开始的可用空间的长度,还有一个记录此区间从右边开始的可用空间的长度。记录这三个量可以互相递推pushup掉三棵线段树上所有的父亲。具体的递推关系可以见代码,但这里必须知道为什么可以递推,因为记录了整个区间从左右端开始延伸的可用空间的长度,递归处理左右儿子,就等价与记录了整个区间上哪些位置可用,哪些位置不可用,就把第一课线段树记录的最大可用空间细节化了,接下来可操作性任意强。


//2720 KB 1063 ms#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#define M 50005#define root 1,n,1#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1using namespace std;int mmax[M<<2],lmax[M<<2],rmax[M<<2]; //mmax记录整个区间的最大连续空位,lmax记录了这个区间从左边开始的连续空位,rmax记录了这个区间从右边开始的连续空位int col[M<<2]; //lazy tagint n,m;void build(int l,int r,int rt){col[rt]=-1;mmax[rt]=lmax[rt]=rmax[rt]=r-l+1;if(l==r){return;}int m=(l+r)>>1;build(lson);build(rson);}void pushup(int rt,int m){lmax[rt]=lmax[rt<<1];rmax[rt]=rmax[rt<<1|1];if(lmax[rt]==m-(m>>1)) lmax[rt]+=lmax[rt<<1|1];if(rmax[rt]==(m>>1)) rmax[rt]+=rmax[rt<<1];mmax[rt]=max(rmax[rt<<1]+lmax[rt<<1|1],max(mmax[rt<<1],mmax[rt<<1|1]) );//mmax[rt]可能是横跨了左右儿子,也可能是左右儿子中的mmax}void pushdown(int rt,int m){if(col[rt]==-1) return;col[rt<<1]=col[rt<<1|1]=col[rt];mmax[rt<<1]=lmax[rt<<1]=rmax[rt<<1] = col[rt]? 0 :m-(m>>1);mmax[rt<<1|1] = lmax[rt<<1|1] =rmax[rt<<1|1]=col[rt]? 0:(m>>1);col[rt]=-1;}int query(int x,int l,int r,int rt){if(mmax[rt]<x){ //也就是mmax[1]<x只有这一种情况return 0;}if(l==r) return l; //这种情况可能发生x=1的时候pushdown(rt,r-l+1);int m=(l+r)>>1;if(mmax[rt<<1]>=x) return query(x,lson);if(rmax[rt<<1]+lmax[rt<<1|1]>=x) return m-rmax[rt<<1]+1; //直接找到答案if(mmax[rt<<1|1]>=x) return query(x,rson);}void update(int L,int R,int c,int l,int r,int rt){if(L<=l&&r<=R){col[rt]=c;mmax[rt]=lmax[rt]=rmax[rt]= c? 0:(r-l+1);return;}pushdown(rt,r-l+1);int m=(l+r)>>1;if(L<=m) update(L,R,c,lson);if(R>m) update(L,R,c,rson);pushup(rt,r-l+1);}int main(){scanf("%d%d",&n,&m);build(root);while(m--){int op;scanf("%d",&op);if(op==1){int x;scanf("%d",&x);int ans=query(x,root);printf("%d\n",ans);if(ans) update(ans,ans+x-1,1,root);}else {int a,b;scanf("%d%d",&a,&b);update(a,a+b-1,0,root);}}return 0;}


0 0
原创粉丝点击