zoukankan      html  css  js  c++  java
  • [ZJOI2013]K大数查询

    有N个位置,M个操作。操作有两种,每次操作是:

    • 1 a b c:表示在第a个位置到第b个位置,每个位置加上一个数c
    • 2 a b c:表示询问从第a个位置到第b个位置,第C大的数是多少。

    算法见注释

    #include<cstdio>
    #define int long long
    using namespace std;
    const int N=5e4+5;
    int n,m,qqq;
    
    struct data{
        int t,a,b,c,idx;
        void read(){
            scanf("%lld%lld%lld%lld",&t,&a,&b,&c);
            if(t==2)idx=++qqq;
        }
    };
    data q[N];
    int ans[N];
    
    struct BIT{//树状数组
        int c[N];
        void add(int pos,int v){
            for(int i=pos;i<=n;i+=i&-i)c[i]+=v;
        }
        int pre(int pos){
            int res=0;
            for(int i=pos;i>=1;i-=i&-i)res+=c[i];
            return res;
        }
    };
    BIT d,dm;
    void add(int l,int r,int v){
        d.add(l,v), d.add(r+1,-v);
        dm.add(l,v*l), dm.add(r+1,-v*(r+1));
    }
    int pre(int pos){return (pos+1)*d.pre(pos)-dm.pre(pos);}
    int sum(int l,int r){return pre(r)-pre(l-1);}
    
    data q1[N],q2[N];
    void solve(int l,int r,int L,int R){
        if(L==R){
            for(int i=l;i<=r;i++)if(q[i].t==2)ans[q[i].idx]=L;
            return;
        }
        int Mid=(L+R)>>1,l1=0,l2=0;
        for(int i=l;i<=r;i++){//计算在[Mid+1,R]区间的数的个数(contri)
            data now=q[i];
            if(now.t==1){
                //只加入[Mid+1,R]的贡献
                if(Mid<now.c&&now.c<=R)add(now.a,now.b,1), q2[++l2]=now;
                else q1[++l1]=now;
            } else {
                int t=sum(now.a,now.b);
                if(now.c<=t)q2[++l2]=now;
                else now.c-=t, q1[++l1]=now;
            }
        }
        for(int i=1;i<=l2;i++)if(q2[i].t==1)add(q2[i].a,q2[i].b,-1);//还原
        
        for(int i=1;i<=l1;i++)q[l+i-1]=q1[i];
        for(int i=1;i<=l2;i++)q[l+l1+i-1]=q2[i];
        solve(l,l+l1-1,L,Mid);
        solve(l+l1,r,Mid+1,R);
    }
    signed main(){
        scanf("%lld%lld",&n,&m);
        for(int i=1;i<=m;i++)q[i].read();
        solve(1,m,0,n);
        for(int i=1;i<=qqq;i++)printf("%lld
    ",ans[i]);
        return 0;
    }
    /*
     * 考虑整体二分。二分答案后,问题转化为
     * - 查询比mid大的数
     * - 区间添加数
     * 整体二分是要求贡献独立的,因此在二分的过程中只考虑跨区间的贡献,并且
     * 必须全部统计完
     */
    
    
  • 相关阅读:
    Good Subarrays(思维)
    Just h-index(主席树裸题)
    强联通入门
    Fragrant numbers(dfs爆搜+区间dp+stoi)
    Mr. Panda and Kakin (RSA 解密+解同余方程+O(1)快速乘)
    Balance of the Force (枚举+线段树+二分图)
    2019 ICPC上海站K.Color Graph
    Wi Know (思维+线段树)
    Linux zookeeper 安装
    javaBIO
  • 原文地址:https://www.cnblogs.com/sshwy/p/10993327.html
Copyright © 2011-2022 走看看