poj 3667 Hotel

// 题意: 旅店登记,有n个房间,有两种操作: 1.找一段最靠前的连续d个空房间; 2.退订[x,x-d+1]段的房间

#include<iostream> //线段树
using namespace std;

struct node
{
int l,r,blank;
int lb,rb; //lb(rb)记录从左(右)端点开始的连续空的线段长
}tree[200010];

void build_tree(int n,int s,int t)
{
tree[n].l=s;tree[n].r=t;
tree[n].blank=tree[n].lb=tree[n].rb=t-s+1;
if(s<t)
{
int mid=(s+t)>>1;
build_tree(2*n,s,mid);
build_tree(2*n+1,mid+1,t);
}
}

void upd_blank(int n)
{
if(tree[n].l==tree[n].r) //如果是叶子结点就退出
return ;

if(tree[n].blank==0)
{
tree[2*n].blank = tree[2*n+1].blank = 0;
tree[2*n].lb = tree[2*n].rb = tree[2*n+1].lb = tree[2*n+1].rb = 0;
}
if(tree[n].blank == tree[n].r-tree[n].l+1)
{
tree[2*n].blank = tree[2*n].r-tree[2*n].l+1;
tree[2*n+1].blank = tree[2*n+1].r-tree[2*n+1].l+1;
tree[2*n].lb = tree[2*n].rb = tree[2*n].r-tree[2*n].l+1;
tree[2*n+1].lb = tree[2*n+1].rb = tree[2*n+1].r-tree[2*n+1].l+1;
}
}
void update(int n)
{
if(tree[n].l==tree[n].r)
return ;
tree[n].blank = tree[2*n].blank+tree[2*n+1].blank;
tree[n].lb = tree[2*n].lb;
if(tree[2*n].lb == tree[2*n].r-tree[2*n].l+1)
tree[n].lb += tree[2*n+1].lb;
tree[n].rb = tree[2*n+1].rb;
if(tree[2*n+1].rb == tree[2*n+1].r-tree[2*n+1].l+1)
tree[n].rb += tree[2*n].rb;
}

void modify_in(int n,int s,int t)
{
upd_blank(n);
if(tree[n].l==s&&tree[n].r==t) //如果一直更新到叶子节点,即tree[n].l==tree[n].r,则会TLE
{

tree[n].blank=tree[n].lb=tree[n].rb=0;
}
else
{
int mid=(tree[n].l+tree[n].r)>>1;
if(s<=mid)
modify_in(2*n,s,min(mid,t));
if(t>mid)
modify_in(2*n+1,max(s,mid+1),t);
update(n);
}
}
void modify_out(int n,int s,int t)
{
upd_blank(n);
if(tree[n].l==s&&tree[n].r==t)
{
tree[n].blank=tree[n].lb=tree[n].rb=tree[n].r-tree[n].l+1;
}
else
{
int mid=(tree[n].l+tree[n].r)>>1;
if(s<=mid)
modify_out(2*n,s,min(mid,t));
if(t>mid)
modify_out(2*n+1,max(s,mid+1),t);
update(n);
}
}
bool query(int n,int len)
{
upd_blank(n);
if(tree[n].r-tree[n].l+1<len||tree[n].blank<len)
return false;
if(tree[n].blank==tree[n].r-tree[n].l+1)
{
modify_in(n,tree[n].l,tree[n].l+len-1); //假如是整个区间都为空的话自然地从左端开始
printf("%d\n",tree[n].l);

return true;
}
//查询最左连续区间时,注意顺序,首先是左子树,然后是跨越左子树和右子树,即原来区间的中间部分,
//然后是右子树,最后如果都不满足的话则输出0
if(tree[n].lb>=len)

{
modify_in(n,tree[n].l,tree[n].l+len-1);
printf("%d\n",tree[n].l);
return true;
}
if(query(2*n,len))
{
update(n);
return true;
}
if(tree[2*n].rb+tree[2*n+1].lb>=len)
{
int a=tree[2*n].rb; //执行后面第一句modify_in()后,tree[2*n].rb的值将会发生改变,所以需要记录下原值
modify_in(2*n,tree[2*n].r-a+1,tree[2*n].r);

modify_in(2*n+1,tree[2*n+1].l,tree[2*n+1].l+len-a-1);
update(n);
printf("%d\n",tree[2*n].r-a+1);
return true;
}
if(query(2*n+1,len))
{
update(n);
return true;
}
return false;
}
int main()
{
int n,m,tag,x,d;
scanf("%d%d",&n,&m);
build_tree(1,1,n);
while(m--)
{
scanf("%d",&tag);
if(tag==1)
{
scanf("%d",&d);
bool ok=query(1,d);
if(!ok)
printf("0\n");
}
else
{
scanf("%d%d",&x,&d);
modify_out(1,x,x+d-1);
}
}
return 0;
}

posted on 2011-07-22 20:42  sysu_mjc  阅读(195)  评论(0编辑  收藏  举报

导航