您的位置:首页 > 理论基础 > 计算机网络

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

因为注释很详尽 。。 要好好学习~

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