• Vases and Flowers(线段树+二分)


    Vases and Flowers(线段树+二分)

    HDU - 4614

    解法一:

    二分区间,线段区间查询空花瓶个数。复杂度(O(nlogn^2))

    由于区间越大,能空花瓶数越多,满足二分单调性。

    操作1:二分pos到n区间的,区间查询二分区间的空花瓶数,找到插花的第一个位置和最后一个位置,然后区间修改

    操作2:输出查询区间值,修改区间。

    #include <iostream>
    #include <cstring>
    #define lch 2*k
    #define rch 2*k+1
    #define mid (l+r)/2
    using namespace std;
    const int N=1e5+7;
    int t;
    int n,m,tree[4*N],tap[4*N];
    void init(int k,int l,int r){
        tap[k]=-1;
        if(l>=r){
            tree[k]=0;
            return;
        }
        init(lch,l,mid);
        init(rch,mid+1,r);
        tree[k]=tree[lch]+tree[rch];
    }
    
    void pushdown(int k,int zl,int zr,int yl,int yr){
        if(tap[k]!=-1){
            tree[lch]=tap[k]*(zr-zl+1);
            tree[rch]=tap[k]*(yr-yl+1);
            tap[lch]=tap[k];
            tap[rch]=tap[k];
            tap[k]=-1;
        }
    }
    
    void update(int k,int l,int r,int ql,int qr,int cost){
        if(ql>qr){
            return;
        }
        if(ql<=l&&r<=qr){
            tree[k]=cost*(r-l+1);
            tap[k]=cost;
            return;
        }
        pushdown(k,l,mid,mid+1,r);
        if(ql<=mid) update(lch,l,mid,ql,qr,cost);
        if(mid+1<=qr) update(rch,mid+1,r,ql,qr,cost);
    
        tree[k]=tree[lch]+tree[rch];
    
    }
    
    int qurey(int k,int l,int r,int ql,int qr){
    
        if(ql>qr){
            return 0;
        }
        if(ql<=l&&r<=qr){
            return tree[k];
        }
        pushdown(k,l,mid,mid+1,r);
        int sum1=0,sum2=0;
        if(ql<=mid) sum1=qurey(lch,l,mid,ql,qr);
        if(mid+1<=qr) sum2=qurey(rch,mid+1,r,ql,qr);
    
        return sum1+sum2;
    }
    
    bool judge(int ql,int qr,int key){
        int cnt=(qr-ql+1)-qurey(1,1,n,ql,qr);
    
        if(cnt>=key){
            return true;
        }else{
            return false;
        }
    }
    int main(){
        scanf("%d",&t);
        while(t--){
            scanf("%d %d",&n,&m);
            //memset(tree,0,sizeof(tree));
            //memset(tap,-1,sizeof(tap));
            init(1,1,n);
            while(m--){
                int op,x,y;
                scanf("%d %d %d",&op,&x,&y);   
                if(op==1){
                    y=min(y,(n-x)-qurey(1,1,n,x+1,n));
                    int jl=x+1,jr=n;
                    while(jl<=jr){
                        int md=(jl+jr)/2;
                        if(judge(x+1,md,y)){
                            jr=md-1;
                        }else{
                            jl=md+1;
                        }
                    }
                    int ll=x+1,rr=jl;
                    while(ll<=rr){
                        int md=(ll+rr)/2;
                        if(judge(md,jl,y)){
                            ll=md+1;
                        }else{
                            rr=md-1;
                        }
                    }
                    if(y==0){
                        printf("Can not put any one.
    ");
                    }else{
                        update(1,1,n,rr,jl,1);
                        printf("%d %d
    ",rr-1,jl-1);
                    }
                }else if(op==2){
                    printf("%d
    ",qurey(1,1,n,x+1,y+1));
                    update(1,1,n,x+1,y+1,0);
               }
            }
            printf("
    ");
        }   
    }
    

    解法二:

    线段树上二分,复杂度(O(nlogn))

    由题意可知,我们需要往(pos)位置插b朵花,也可能插少于(b)朵花,即为b朵花和(pos)(n)位置的空花瓶数取最小值。

    操作1:

    为了方便从(1)(n)线段树二分,我们查询(1)(pos-1)位置的空花瓶数,加上(pos)位置之后的需要插花的数量,设为(cnt1)

    在区间1到n线段树上二分查找从1开始到第cnt1空花瓶位置,设左子树的空花瓶数为(tem),若(tem)数大于或等于(cnt1),则往左子树查找,否则往右子树查找(cnt1-tem),找到第(cnt1)位置的空花瓶的下标值,即为最后插花的位置。

    查询开始插花的位置,即查询(pos)(n)的空花瓶数,为(cnt2),同理二分查找(n)开始到(cnt2)个空花瓶位置,即为开始插花的位置。

    最后区间修改。

    操作2:

    区间查询和修改。

    #include <iostream>
    #define lch 2*k
    #define rch 2*k+1
    #define mid (l+r)/2
    using namespace std;
    const int N=1e5+7;
    int tree[4*N],tap[4*N];
    int t,n,q;
    void init(int k,int l,int r){
        tap[k]=-1;
        if(l>=r){
            tree[k]=1;
            return;
        }
        init(lch,l,mid);
        init(rch,mid+1,r);
        tree[k]=tree[lch]+tree[rch];
    }
    void pushdown(int k,int zl,int zr,int yl,int yr){
        if(tap[k]!=-1){
            tree[lch]=tap[k]*(zr-zl+1);
            tree[rch]=tap[k]*(yr-yl+1);
            tap[lch]=tap[k];
            tap[rch]=tap[k];
            tap[k]=-1;
        }
    }
    void update(int k,int l,int r,int ql,int qr,int cost){
        if(ql>qr){
            return;
        }
        if(ql<=l&&r<=qr){
            tree[k]=cost*(r-l+1);
            tap[k]=cost;
            return;
        }
        pushdown(k,l,mid,mid+1,r);
        if(ql<=mid) update(lch,l,mid,ql,qr,cost);
        if(mid+1<=qr) update(rch,mid+1,r,ql,qr,cost);
        tree[k]=tree[lch]+tree[rch];
    }
    
    int qurey(int k,int l,int r,int ql,int qr){
        if(ql>qr){
            return 0;
        }
        if(ql<=l&&r<=qr){
            return tree[k];
        }
        pushdown(k,l,mid,mid+1,r);
        int sum1=0,sum2=0;
        if(ql<=mid) sum1=qurey(lch,l,mid,ql,qr);
        if(mid+1<=qr) sum2=qurey(rch,mid+1,r,ql,qr);
        return sum1+sum2;
    }
    
    int searchR(int k,int l,int r,int cnt){
        if(l>=r){
            return l;
        }
        pushdown(k,l,mid,mid+1,r);
        int tem=tree[lch];
        int inx=-1;
        if(tem>=cnt){
            inx=searchR(lch,l,mid,cnt);
        }else{
            inx=searchR(rch,mid+1,r,cnt-tem);
        }
        return inx;
    }
    
    int searchL(int k,int l,int r,int cnt){
        if(l>=r){
            return l;
        }
        pushdown(k,l,mid,mid+1,r);
        int tem=tree[rch];
        int inx=-1;
        if(tem>=cnt){
            inx=searchL(rch,mid+1,r,cnt);
            
        }else{
            inx=searchL(lch,l,mid,cnt-tem);
        }
        return inx;
    }
    int main(){
        scanf("%d",&t);
        while(t--){
            scanf("%d %d",&n,&q);
            init(1,1,n);
            while(q--){
                int op,a,b;
                scanf("%d %d %d",&op,&a,&b);
                
                if(op==1){
                    if(qurey(1,1,n,a+1,n)==0){
                        printf("Can not put any one.
    ");
                        continue;
                    }
                    int cnt1=min(qurey(1,1,n,1,n),b+qurey(1,1,n,1,a));
                    int inx1=searchR(1,1,n,cnt1);
                    int cnt2=qurey(1,1,n,a+1,n);
                    int inx2=searchL(1,1,n,cnt2);
                    update(1,1,n,inx2,inx1,0);
                    printf("%d %d
    ",inx2-1,inx1-1);
                }
                else if(op==2){
                    printf("%d
    ",(b-a+1)-qurey(1,1,n,a+1,b+1));
                    update(1,1,n,a+1,b+1,1);
                }
                
            }
            printf("
    ");
        }
    }
    
  • 相关阅读:
    select、poll和epoll
    Linux 常用命令之文件和目录
    SmartPlant Review 帮助文档机翻做培训手册
    SmartPlant Foundation 基础教程 3.4 菜单栏
    SmartPlant Foundation 基础教程 3.3 标题栏
    SmartPlant Foundation 基础教程 3.2 界面布局
    SmartPlant Foundation 基础教程 3.1 DTC登陆界面
    SmartPlant Foundation 基础教程 1.4 SPF架构
    SmartPlant Foundation 基础教程 1.3 SPF其他功能
    SmartPlant Foundation 基础教程 1.2 SPF集成设计功能
  • 原文地址:https://www.cnblogs.com/kksk/p/14045392.html
Copyright © 2020-2023  润新知