poj3667 Hotel (线段树--区间合并)转自网络【2】

来源:互联网 发布:甲骨文软件招聘骗局 编辑:程序博客网 时间:2024/04/27 17:28

题目大意:有一段长为n的线段,在这条线段上进行操作:1.找出最靠前的长度为l的空线段,并把一个长为l的线段插入在这个地方.2.删除从某点开始长为l的一段线段(有可能并不存在,总之就是把这个区间清空).输出每次插入操作的位置.

 一个有 N 个连续房间的旅馆,对 m 次询问对应两种操作。

    1  a      询问是不是有连续长度为a的空房间,有的话住进最左边
         2 a b    将[a,a+b-1]的房间清空

分析: 区间合并类线段树。

         update  成段更新 

         query   找到满足条件的最左端点

代码转自http://www.notonlysuccess.com/index.php/segment-tree-complete/

注释转自http://blog.csdn.net/h2952220/article/details/7911622

照着大牛的代码打一遍 。。顿时感觉好清爽。。学习中。。

#include<iostream>#include<cstring>#include<cstdio>using namespace std;#define lson l,m,rt<<1          //函数用左儿子#define rson m+1,r,rt<<1|1      //函数用右儿子#define havemid int m=(l+r)>>1  //取节点中点#define left (rt<<1)            //左儿子#define right (rt<<1|1)         //右儿子const int maxn=50005;int lsum[maxn<<2];              //该区间左端开始的空房间数目int rsum[maxn<<2];              //该区间右端开始的空房间数目int msum[maxn<<2];              //该区间里最长的连续空房间的数目int cover[maxn<<2];             //延迟标志 -1表示无需更新,1表示有人入住把空房间数清零,0需要把空房间数堆满void pushdown(int rt,int len){    if(cover[rt]!=-1){        cover[left]=cover[right]=cover[rt];//延迟标志向下传递        msum[left]=lsum[left]=rsum[left]=cover[rt]?0:len-(len>>1);//如果延迟标志为0,则将区间内空房间数清零        msum[right]=lsum[right]=rsum[right]=cover[rt]?0:len>>1;//如果延迟标志为1,则将区间内空房间数堆满        cover[rt]=-1;    }}void pushup(int rt,int len){    lsum[rt]=lsum[left];//无论左端开始数的空房间数是否充满整个空间(即即使要加上右儿子从左端开始数的空房间数),都要先把左儿子的房间数复制给父亲的rooml    rsum[rt]=rsum[right];//同上    if(lsum[rt]==len-(len>>1))lsum[rt]+=lsum[right];//如果左儿子的rooml充满区间,则加上右儿子的rooml    if(rsum[rt]==len>>1)rsum[rt]+=rsum[left];//如果右儿子的roomr充满区间,则加上左儿子的roomr    msum[rt]=max(lsum[right]+rsum[left],max(msum[left],msum[right]));//roomr[left] + rooml[right]表示合并区间时产生的连续不断的空房间数}void build(int l,int r,int rt){    msum[rt]=lsum[rt]=rsum[rt]=r-l+1;    cover[rt]=-1;    if(l==r)return ;    havemid;    build(lson);    build(rson);}void update(int L,int R,int c,int l,int r,int rt){    if(L<=l&&r<=R){        msum[rt]=lsum[rt]=rsum[rt]=c?0:r-l+1;//根据延迟标志选择性更新        cover[rt]=c;        return ;    }    pushdown(rt,r-l+1);    havemid;    if(L<=m)update(L,R,c,lson);//如果左儿子还有没更新的就更新    if(R>m)update(L,R,c,rson);//同上    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);//更新未更新的儿子节点    havemid;    if(msum[left]>=w)return query(w,lson);//一直找左儿子的最大连续空房间,一直找到左儿子的roommid不满足,则这个区间一定落在中间的区间,否则在右区间    else if(rsum[left]+lsum[right]>=w)return m - rsum[rt<<1] + 1;    else query(w,rson);}int main(){    int n,m,t,a,b;    while(scanf("%d%d",&n,&m)!=EOF)    {        build(1,n,1);        while(m--)        {            scanf("%d",&t);            if(t==1){                scanf("%d",&a);                if (msum[1]<a)printf("0\n");//如果整个区间都没有连续a的长度 输出0 否则查询时会到奇怪的地方 更新就出错了                else {                    int res=query(a,1,n,1);                    printf("%d\n",res);                    update(res,res+a-1,1,1,n,1);                }            }            else {                scanf("%d%d",&a,&b);                update(a,a+b-1,0,1,n,1);            }        }    }    return 0;}


原创粉丝点击