zoukankan      html  css  js  c++  java
  • [BZOJ 3110][Zjoi2013]K大数查询(整体二分+BIT)

    Description

    有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
    如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。

    Solution

    标解似乎是树套树?=w=

    二分答案。

    对于每一个修改,如果c>mid就进行操作,并划到后一个集合里,反之加入前一个集合;对于每一个询问,如果a-b中的数大于c个就划到后一个集合里,反之要减掉a-b中数的个数并加入前一个集合。然后对于两个集合递归下去blahblah

    其中数的个数可以用区间修改区间查询的树状数组来维护(树状数组大法好…本来用的是线段树然而打清空标记的操作写得太乱调不下去了)

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #define MAXN 50005
    typedef long long LL;
    using namespace std;
    int n,m,id[MAXN],t1[MAXN],t2[MAXN],T=0;
    LL ans[MAXN];
    struct Node1
    {
        int opt,a,b;
        LL c;
    }O[MAXN];
    struct BIT
    {
        LL c[MAXN];int sign[MAXN];
        int lowbit(int x){return x&-x;}
        void add(int pos,int x)
        {
            while(pos<=n)
            {
                if(sign[pos]!=T)c[pos]=0,sign[pos]=T;
                c[pos]+=x,pos+=lowbit(pos);
            }
        }
        LL query(int pos)
        {
            LL res=0;
            while(pos>0)
            {
                if(sign[pos]!=T)c[pos]=0,sign[pos]=T;
                res+=c[pos],pos-=lowbit(pos);
            }
            return res;
        }
    }c1,c2;
    void ADD(int a,int b)
    {
        c1.add(a,1),c1.add(b+1,-1);
        c2.add(a,a),c2.add(b+1,-b-1);
    }
    LL QUERY(int a,int b)
    {
        LL res=0;
        res+=(b+1)*c1.query(b)-c2.query(b);
        res-=a*c1.query(a-1)-c2.query(a-1);
        return res;
    }
    LL read()
    {
        LL x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){
            if(c=='-')f=-1;c=getchar();
        }
        while(c>='0'&&c<='9'){
            x=x*10+c-'0';c=getchar();
        }
        return x*f;
    }
    void solve(int l,int r,int ansl,int ansr)
    {
        if(l>r)return;
        if(ansl==ansr)
        {
            for(int i=l;i<=r;i++)
            if(O[id[i]].opt==2)ans[id[i]]=ansl;
            return;
        }
        int mid=(ansl+ansr)>>1;
        int j=1,k=1;
        T++;
        for(int i=l;i<=r;i++)
        {
            int idx=id[i];
            if(O[idx].opt==1)
            {
                if(O[idx].c<=mid)t1[j++]=idx;
                else t2[k++]=idx,ADD(O[idx].a,O[idx].b);
            }
            else
            {
                LL res=QUERY(O[idx].a,O[idx].b);
                if(res>=O[idx].c)t2[k++]=idx;
                else t1[j++]=idx,O[idx].c-=res;
            }
        }
        --j,--k;
        for(int i=1;i<=j;i++)id[l+i-1]=t1[i];
        for(int i=1;i<=k;i++)id[l+j+i-1]=t2[i];
        solve(l,l+j-1,ansl,mid),solve(l+j,r,mid+1,ansr);
        
    }
    int main()
    {
        n=read(),m=read();
        for(int i=1;i<=m;i++)
        O[i].opt=read(),O[i].a=read(),O[i].b=read(),O[i].c=read(),id[i]=i;
        solve(1,m,-n,n);
        for(int i=1;i<=m;i++)
        if(O[i].opt==2)printf("%d
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    bzoj1014: [JSOI2008]火星人prefix
    bzoj1934: [Shoi2007]Vote 善意的投票&&bzoj2768:[JLOI2010]冠军调查
    bzoj2705: [SDOI2012]Longge的问题
    bzoj4653: [Noi2016]区间
    bzoj2456: mode
    bzoj5018: [Snoi2017]英雄联盟
    关于树论【左偏树】
    caioj1522: [NOIP提高组2005]过河
    caioj1421&&hdu2167: [视频]【状态压缩】选数
    Linux下全局安装composer方法
  • 原文地址:https://www.cnblogs.com/Zars19/p/6900922.html
Copyright © 2011-2022 走看看