zoukankan      html  css  js  c++  java
  • 线段树+二分(笔试题第一次遇到线段树相关的,记录下)

    博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~
    https://www.cnblogs.com/chenxiwenruo/p/9609857.html
    特别不喜欢那些随便转载别人的原创文章又不给出链接的
    所以不准偷偷复制博主的博客噢~~

    题意:
    有1,2,~n层香槟的塔,如果第i层香槟满了,那么多余的水会往下一层(i+1)流去
    现给两种操作:
    2 x v 即往第x层倒入体积为v的香槟
    1 x 查询第x层装了多少体积的香槟
    输入:
    n m
    n个数ai,表示每层塔的容量
    接下来m行即为m个操作
    当1 x的时候,输出对应的第x层容量

    1<=n,m<=200000

    由于m范围,所以暴力肯定是不可能的,思路是用线段树,这样时间复杂度就是NlgN
    构建一棵线段树,叶子节点即为1~n层的剩余容量。
    当往x层添加v容量的香槟,在[x,n]区间二分查找k,使得[x,k-1]的容量小于v,但[x,k]的容量>=v
    然后这样就把[x,k-1]区间清零,叶子节点k的容量减去v-[x,k-1]
    对于查询的时候,只要查询叶子节点的,结果为a[i]-left_sum[x,x]

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #define lson rt<<1,L,mid
    #define rson rt<<1|1,mid+1,R
    
    using namespace std;
    const int maxn=1000005;
    int n,m;
    long long a[200000+5];
    struct Node{
        long long left_sum;
        bool lazy;
    }tree[maxn<<4];
    
    void pushUp(int rt){
        tree[rt].left_sum=tree[rt<<1].left_sum+tree[rt<<1|1].left_sum;
    }
    void pushDown(int rt){
        if(tree[rt].lazy){
            tree[rt<<1].left_sum=0;
            tree[rt<<1|1].left_sum=0;
            tree[rt<<1].lazy=tree[rt<<1|1].lazy=true;
            tree[rt].lazy=false;
        }
    }
    void build(int rt,int L,int R){
        if(L==R){
            tree[rt].left_sum=a[L];
            tree[rt].lazy=false;
            return ;
        }
        int mid=(L+R)>>1;
        build(lson);
        build(rson);
        pushUp(rt);
    }
    
    void update(int rt,int L,int R,int l,int r,long long val){
        if(l<=L&&R<=r){
            if(val==0){
                tree[rt].left_sum=0;
                tree[rt].lazy=true;
            }
            else{
                tree[rt].left_sum-=val;
                //pushUp(rt);
            }
            return;
        }
        pushDown(rt);
        int mid=(L+R)>>1;
        if(l<=mid)
            update(lson,l,r,val);
        if(r>mid)
            update(rson,l,r,val);
        pushUp(rt);
    }
    
    long long query(int rt,int L,int R,int l,int r){
        long long ret=0;
        if(l>r)
            return 0;
        if(l<=L&&R<=r){
            return tree[rt].left_sum;
        }
        pushDown(rt);
        int mid=(L+R)>>1;
        if(l<=mid)
            ret+=query(lson,l,r);
        if(r>mid)
            ret+=query(rson,l,r);
        return ret;
    }
    /*
    二分查找k
    使得left_sum[x,k-1]<v<=left_sum[x,k]
    若left_sum[x,n]<v
    则返回n+1
    */
    int binary_searchs(int x,int n,int v){
        int l=x-1,r=n+1;
        int mid;
        while(l<r-1){
            mid=(l+r)>>1;
            //printf("%d %d %d
    ",l,mid,r);
            if(query(1,1,n,l,mid)>=v)
                r=mid;
            else{
                l=mid;
            }
        }
        return r;
    }
    int main()
    {
        int x;
        long long v;
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
        }
        build(1,1,n);
        int id;
        for(int i=0;i<m;i++){
            scanf("%d",&id);
            if(id==2){
                scanf("%d %lld",&x,&v);
                int k=binary_searchs(x,n,v);
                int left=v-query(1,1,n,x,k-1);
                //printf("k:%d left:%d
    ",k,left);
    
                //下面当时写成了了update(1,1,n,1,k-1,0)
                //导致只过了60%的样例,不过没想到数据这么弱,这么个大错误还能过60%样例
                if(k>x)
                    update(1,1,n,x,k-1,0);  //将[x,k-1]区间清零,即剩余容量为0
                if(k<=n)
                    update(1,1,n,k,k,left); //将[k,k]区间剩余容量-left
            }
            else{
                scanf("%d",&x);
                long long ans=query(1,1,n,x,x);
                printf("%lld
    ",a[x]-ans);
            }
        }
        return 0;
    }
  • 相关阅读:
    微信登录时用户信息无法写入数据库
    首次配置路由出现404的问题
    php登录模块出现循环重定向的问题
    关于动态生成dom绑定事件的问题
    将博客搬至CSDN
    C++ this指针的详解
    zigbee 中ZDO的理解
    zigbee端口的理解
    c语言的一些易错知识积累
    zigbee 安全通信加密链接密钥
  • 原文地址:https://www.cnblogs.com/chenxiwenruo/p/9609857.html
Copyright © 2011-2022 走看看