• [线段树] (h) poj3667 (区间合并)


    poj3667 Hotel

    如在阅读本文时遇到不懂的部分,请在评论区询问,或跳转 线段树总介绍


    【题目大意】

    有一个旅馆,有N个房间排成一排,现在有两种操作,第一是有X个顾客要入住连续的X个房间,
    要求输出最小的左端点的位置,不能满足就输出0,第二是将以L开始,长度为X的连续房间清空。

    【输入文件】

    第一行两个数N,M,表示房间数和操作数

    接下来M行,每行有两种情况:

    1 X 表示操作1

    2 L X 表示操作2

    【输出文件】

    对于每一个1操作,输出答案。

    题即为求最靠左的连续区间并置满以及把一段区间置空。

    那么我们的线段树正式进入了区间合并的部分

    0表示没有牛,1表示住了牛

    用pre(前驱)表示该区间内的前导零个数,last(后继,用suf比较好但当时写了last不想改了,一个意思),表示后导零个数,Maxilen表示区间内最大连续0的个数

    ,tag表示该区间内全部置为tag(初值为-1)

    pushup注意特殊情况,若 左/右 区间的 前驱/后继 完全覆盖了 左/右 区间,要特殊处理

    if(pre[LS]==mid-l+1)pre[rt]=pre[RS]+pre[LS];
    else pre[rt]=pre[LS];
    if(last[RS]==r-mid)last[rt]=last[RS]+last[LS];
    else last[rt]=last[RS];
    Maxilen[rt]=max (Maxilen[LS] ,Maxilen[RS] ,pre[RS]+last[LS] );
    //最大连续区间可能在 左边/右边/中间(所以为什么维护前驱后继)

    pushdown

    整段操作,赋0 or 赋1

     tag[LS]=tag[RS]=tag[rt];
     MaxiLen[LS]=pre[LS]=last[LS]=!tag[rt]?(mid-l+1):0;
     MaxiLen[RS]=pre[RS]=last[RS]=!tag[rt]?(r-mid):0;
     tag[rt]=-1; 

    代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    using namespace std;
    const int N=2e6+3;
    int pre[N<<2],last[N<<2],MaxiLen[N<<2],tag[N<<2];
    int n,m,L;
    //tag -1 -> Nothing 0 ; 0/1 -> get to 0/1 
    #define LS (rt<<1)
    #define RS (LS|1)
    void pushup(int rt,int l,int r){
        MaxiLen[rt]=max(max(MaxiLen[LS],MaxiLen[RS]),pre[RS]+last[LS]);
        int mid=l+r>>1;
        if(pre[LS] == mid-l+1)pre[rt]=mid-l+1+pre[RS];
        else pre[rt]=pre[LS];
        if(last[RS] == r-mid)last[rt]=r-mid+last[LS];
        else last[rt]=last[RS];
    }
    void build(int rt,int l,int r){
        pre[rt]=last[rt]=MaxiLen[rt]=r-l+1;
        tag[rt]=-1;
        if(l==r)return;
        int mid=l+r>>1;
        build(LS,l,mid);
        build(RS,mid+1,r);
        //pushup(rt,l,r);
    }
    void pushdown(int rt,int l,int r){
        if(tag[rt] == -1)return;
        tag[LS]=tag[RS]=tag[rt];
        int mid=l+r>>1;
        MaxiLen[LS]=pre[LS]=last[LS]=!tag[rt]?(mid-l+1):0;
        MaxiLen[RS]=pre[RS]=last[RS]=!tag[rt]?(r-mid):0;
        tag[rt]=-1; return;
    }
    void update(int rt,int l,int r,int x,int y,int p){
        if(l>=x&&r<=y){
            tag[rt]=p; //直接覆盖
            MaxiLen[rt]=!p?(r-l+1):0;
            pre[rt]=last[rt]=!p?(r-l+1):0;
            return;
        }pushdown(rt,l,r);
        int mid=l+r>>1;
        if(x<=mid) update(LS,l,mid,x,y,p);
        if(y>mid) update(RS,mid+1,r,x,y,p);
        pushup(rt,l,r); return;
    }
    int query(int rt,int l,int r,int LEN){
        if(l==r)return l;  //一个点,因为一直优先往左,所以这个点一定是最靠左的
        int mid=l+r>>1;
        pushdown(rt,l,r);
        if(MaxiLen[LS]>=LEN) return query(LS,l,mid,LEN);
        if(last[LS]+pre[RS]>=LEN) return mid-last[LS]+1; //取得左儿子后继的开端
        if(MaxiLen[RS]>=LEN) return query(RS,mid+1,r,LEN);
        return 0; //if(MaxiLen[rt]<LEN)return 0;
    }
    int main(){
        scanf("%d%d",&n,&m);
            build(1,1,n);
            int ty,x,L;
            while(m--){
                scanf("%d",&ty);
                if(ty==1){
                    scanf("%d",&x);
                    L=query(1,1,n,x);
                    printf("%d
    ",L);
                    if(L)update(1,1,n,L,L+x-1,1);
                }else {
                    scanf("%d%d",&L,&x);
                    update(1,1,n,L,L+x-1,0);
                }
            }
        
        return 0;
    }

    颜色是不是很好看qwq

    End

  • 相关阅读:
    6
    5
    4
    3
    Hive常用的DCL(Data Control Language)数据操作
    Hive常用的DQL(Data Query Language)数据操作
    Hive常用的DML(Data Manipulation Language)数据操作
    Hive常用的DDL(Data Definition Language)数据操作
    Hive常用的数据类型概述
    Hive的JDBC环境部署
  • 原文地址:https://www.cnblogs.com/lsy263/p/11229039.html
Copyright © 2020-2023  润新知