zoukankan      html  css  js  c++  java
  • 【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
  • 相关阅读:
    jQuery 源码解析(二十四) DOM操作模块 包裹元素 详解
    jQuery 源码解析(二十三) DOM操作模块 替换元素 详解
    jQuery 源码解析(二十二) DOM操作模块 复制元素 详解
    jQuery 源码分析(二十一) DOM操作模块 删除元素 详解
    jQuery 源码分析(二十) DOM操作模块 插入元素 详解
    jQuery 源码分析(十九) DOM遍历模块详解
    python 简单工厂模式
    python 爬虫-协程 采集博客园
    vue 自定义image组件
    微信小程序 image组件坑
  • 原文地址:https://www.cnblogs.com/onioncyc/p/7522470.html
Copyright © 2011-2022 走看看