POJ 3667 Hotel

Hotel


线段树:区间合并。
首次写区间合并,开始的时候没有想明白怎么做。看了别人的解题报告,终于明白了操作的各种过程。
其实与前面的线段树题目没什么太大的区别。主要是在线段树节点保存的值上多增加了一些。
首先看节点域:
struct Tree{
  int l , r , lans , rans , mans , f ;
}
一共五个变量,l,r的含义与之前相同,为该区间的范围。lans表示的是该区间左端点起连续的空房间的个数,对应的rans为该区间右端点起连续的空房间的个数,mans为该区间最长的空房间的个数,f为lazy标记用。
对于查询操作1 x,如果查询到以元节点,那么这个点肯定是查询的结果,返回,对于非元节点意外的节点,我们都需要将该节点的信息更新到子树中。然后我们看当前节点c的左子树上是不是有足够的空房间,这里就是判断左子树上最长区间的长度是不是大于等于给定的房间个数x,如果有显然我们应该到左子树上继续查询;然后我们看中间连续的区间是不是存在(因为我们将区间划分成左子树和右子树的时候,将连续的区间分开了),所以判断左子树右连续(也就是tree[L(c)].rans)区间个数与右子树左连续(也就是tree[R(c)].lans)之和是不是有足够的房间,如果有显然可以直接计算出所要查询的房间的最小编号:tree[L(c)].r - tree[L(c)].rans + 1 .如果还没有那么,显然我们应该看右子树中最长的区间的区间长度。
那么在看更新操作:就是将某一段赋值为0或者为1,这里我用0表示该区间是可用的,1表示该区间不可用。如果需要修改的区间与节点表示的区间相等,就是直接更新该区间的值了。如果不相等,和一般应用的线段树一样。由于使用了lazy标记,那么我们就需要将信息向下传递,使用pushDown()函数。然后,看区间是在左子树,还是在右子树,或者两个区间都有。紧接着,我们需要将子树的信息更新到父节点。对于父节点的lans ,rans都比较好更新,而mans的可能取值,肯定是在左子树的mans,右子树的mans,以及区间的交叉和:tree[L(c)].rans + tree[R(c)].lans中。


/*
author    : csuchenan
LANG      : c++
PROG      : POJ3667 hotel
Algorithm : Segment Tree 
*/
#include <cstdio>
#include <cstring>

#define maxn 50005
#define L(x) x<<1
#define R(x) x<<1|1
#define M(x , y) (x + y)>>1
#define Max(x , y) x > y ? x : y
#define Min(x , y) x < y ? x : y

struct Tree{
    int l ;
    int r ;
    int f ;
    //int c ;//是否被覆盖,0 代表未覆盖,1,已经覆盖,-1混合区间
    int lans ;//从该区间左端点起的最长的序列
    int rans ;//从该区间右端点起的最长的序列
    int mans ;//该区间最长的序列
}tree[maxn * 3] ;

void build(int l , int r , int c){
    tree[c].l = l ;
    tree[c].r = r ;
    //tree[c].c = 0 ;
    tree[c].f = -1 ;
    tree[c].lans = r - l + 1 ;
    tree[c].rans = r - l + 1 ;
    tree[c].mans = r - l + 1 ;
    if(l == r)
        return ;

    int m = M(l , r) ;
    build(l , m , L(c)) ;
    build(m + 1 , r , R(c)) ;
}

void pushDown(int c){
    int l = L(c) ;
    int r = R(c) ;

    if(tree[c].f >= 0){
        tree[l].f = tree[c].f ;
        tree[r].f = tree[c].f ;
        //tree[l].c = tree[l].f ;
        //tree[r].c = tree[r].f ;

        if(tree[c].f){
            tree[l].lans = 0 ;
            tree[l].rans = 0 ;
            tree[l].mans = 0 ;

            tree[r].lans = 0 ;
            tree[r].rans = 0 ;
            tree[r].mans = 0 ;
        }
        else{
            tree[l].lans = tree[l].r - tree[l].l + 1 ;
            tree[l].rans = tree[l].r - tree[l].l + 1 ;
            tree[l].mans = tree[l].r - tree[l].l + 1 ;

            tree[r].lans = tree[r].r - tree[r].l + 1 ;
            tree[r].rans = tree[r].r - tree[r].l + 1 ;
            tree[r].mans = tree[r].r - tree[r].l + 1 ;
        }
        tree[c].f = -1 ;
    }
}

void pushUp(int c){
    int l = L(c) ;
    int r = R(c) ;

    tree[c].mans = Max(tree[l].mans , (Max(tree[r].mans , tree[r].lans + tree[l].rans)) ) ;
    tree[c].lans = tree[l].lans ;
    tree[c].rans = tree[r].rans ;

    if(tree[l].lans == tree[l].r - tree[l].l + 1){
        tree[c].lans += tree[r].lans ;
    }
    if(tree[r].rans == tree[r].r - tree[r].l + 1){
        tree[c].rans += tree[l].rans ;
    }
    //if(tree[l].c != tree[r].c)
    //    tree[c].c = -1 ;
    //else
    //    tree[c].c = tree[l].c ;
}

void update(int op , int x , int y , int c){
    if(tree[c].l == x  && tree[c].r == y){
        //tree[c].c = op ;
        tree[c].f = op ;
        //如果被覆盖为1
        if(op){
            tree[c].lans = 0 ;
            tree[c].rans = 0 ;
            tree[c].mans = 0 ;
        }
        else{
            tree[c].lans = tree[c].r - tree[c].l + 1 ;
            tree[c].rans = tree[c].r - tree[c].l + 1 ;
            tree[c].mans = tree[c].r - tree[c].l + 1 ;
        }
        return ;
    }
    pushDown(c) ;

    int m = M(tree[c].l , tree[c].r) ;
    if(y <= m){
        update(op , x , y , L(c)) ;
    }
    else if(x > m){
        update(op , x , y , R(c)) ;
    }
    else{
        update(op , x , m , L(c)) ;
        update(op , m + 1 , y , R(c)) ;
    }
    pushUp(c);
}

int query(int x , int c){
    if(tree[c].l == tree[c].r)
        return tree[c].l ;

    pushDown(c) ;

    if(tree[L(c)].mans >= x){
        return query(x , L(c)) ;
    }
    else if(tree[L(c)].rans + tree[R(c)].lans >= x ){
        return tree[L(c)].r - tree[L(c)].rans + 1 ;
    }
    else if(tree[R(c)].mans >= x){
        return query(x , R(c)) ;
    }
    return 0 ;
}


int main(){
    int n ;
    int m ;
    int x ;
    int y ;
    int op ;

    scanf("%d%d" , &n ,&m) ;
    build(1 , n , 1) ;
    for(int k(0) ; k < m ; k ++){
        scanf("%d" , &op) ;
        if(op == 1){
            scanf("%d" , &x) ;
            int room = query(x , 1) ;
            printf("%d\n" , room) ;
            if(room)
                update(1 , room , room + x - 1 , 1)   ;
        }
        else{
            scanf("%d%d" , &x , &y) ;
            update(0 , x , x + y - 1 , 1) ;
        }
    }
    return 0 ;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值