• 【BZOJ】1593: [Usaco2008 Feb]Hotel 旅馆


    【算法】线段树(经典线段树上二分)

    【题意】n个房间,m个询问,每次订最前的连续x个的空房间,或退订从x开始y个房间,求每次订的最左房间号。

    【题解】关键在于找连续x个空房间,经典二分。

    线段树标记sum,lsum,rsum,表示最长连续房间,从左开始最长连续房间,从右开始最长连续房间。

    对于区间k,如果k.sum<x,则无解。

    否则,如果l(k).sum>=x,则在左区间。

    否则,如果l(k).rsum+r(k).lsum>=x,则在中间,那么l(k).r-l(k).rsum+1就是答案。

    否则,则在右区间。

    这样可以准确的定位,也体现了线段树被称之为区间树的特点,可以将询问分成若干个完整的区间,只要维护区间信息即可。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn=50010;
    struct tree{int l,r,lsum,rsum,sum,delta;}t[maxn*4];
    int n,m;
    
    void build(int k,int l,int r){
        t[k].l=l;t[k].r=r;t[k].sum=t[k].lsum=t[k].rsum=r-l+1;t[k].delta=-1;
        if(l==r)return;
        int mid=(l+r)>>1;
        build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    }
    void modify(int k,int x){
        if(x==1){
            t[k].lsum=t[k].rsum=t[k].sum=0;
        }
        else{
            t[k].lsum=t[k].rsum=t[k].sum=t[k].r-t[k].l+1;
        }
    }
    void update(int k){
        t[k].sum=max(t[k<<1].rsum+t[k<<1|1].lsum,max(t[k<<1].sum,t[k<<1|1].sum));
        t[k].lsum=t[k<<1].lsum;if(t[k<<1].lsum==t[k<<1].r-t[k<<1].l+1)t[k].lsum+=t[k<<1|1].lsum;
        t[k].rsum=t[k<<1|1].rsum;if(t[k<<1|1].rsum==t[k<<1|1].r-t[k<<1|1].l+1)t[k].rsum+=t[k<<1].rsum;
    }
    void push_down(int k){
        if(~t[k].delta){
            modify(k<<1,t[k].delta);t[k<<1].delta=t[k].delta;
            modify(k<<1|1,t[k].delta);t[k<<1|1].delta=t[k].delta;//传标记 
            t[k].delta=-1;
        }
    }
    int ask(int k,int x){
        push_down(k);
        if(t[k].sum<x)return 0;
        if(t[k<<1].sum>=x)return ask(k<<1,x);
        if(t[k<<1].rsum+t[k<<1|1].lsum>=x)return t[k<<1].r-t[k<<1].rsum+1;
        return ask(k<<1|1,x);
    }
    void insert(int k,int l,int r,int x){
        if(l<=t[k].l&&t[k].r<=r)t[k].delta=x,modify(k,x);//打标记 
        else{
            push_down(k);
            int mid=(t[k].l+t[k].r)>>1;
            if(l<=mid)insert(k<<1,l,r,x);
            if(r>mid)insert(k<<1|1,l,r,x);
            update(k);
        }
    }
            
    int main(){
        scanf("%d%d",&n,&m);
        build(1,1,n);
        int p,x,y;
        for(int i=1;i<=m;i++){
            scanf("%d",&p);
            if(p==1){
                scanf("%d",&x);
                printf("%d
    ",y=ask(1,x));
                if(y)insert(1,y,y+x-1,1);
            }
            else{
                scanf("%d%d",&x,&y);
                insert(1,x,x+y-1,0);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    flutter 右滑返回上一页
    flutter 的Animation简单了解
    Flutter Offstage、Visibility隐藏/可见
    flutter手势
    Flutter生命周期
    flutter 路由动画
    flutter 保持页面状态
    flutter 不规则底部工具栏实现
    flutter 主页面底部导航栏实现以及主题风格设置
    flutter DropdownButton使用
  • 原文地址:https://www.cnblogs.com/onioncyc/p/7522470.html
Copyright © 2020-2023  润新知