您的位置:首页 > 其它

【线段树区间合并】POJ3667-Hotel

2016-01-31 09:55 316 查看
【题意】

一段区间初始均为可行。有两个操作:

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: