zoukankan      html  css  js  c++  java
  • 【BZOJ 1901】【Zju 2112】 Dynamic Rankings 动态K值 树状数组套主席树模板题

    达神题解传送门:http://blog.csdn.net/dad3zz/article/details/50638360


    说一下我对这个模板的理解:

    看到这个方法很容易不知所措,因为动态K值需要套树状数组,而我一开始根本不知道该怎么套,,

    学习吧,,,

    然后我自己脑补如果不套会如何?后来想到是查询O(logn),修改是O(nlogn),很明显修改的复杂度太大了,为了降低修改的复杂度,我们只得套上树状数组来维护前缀和使它的n的复杂度降低为logn,从而修改的复杂度变为O(log2n)。但因为我们套了树状数组,所以查询的复杂度也不得不上升到O(log2n),但从整体上看来这些牺牲是值得的,总复杂度最终是O(nlog2n)。

    这些都太简单了是吧,,果然我太傻,,

    比较的时候和普通的主席树不同,不再是两个做差了,而是把树状数组中的节点放到两个池子里做差,我的code里是L和R两个池子,,

    至于为什么要离线,我思考了很久,,,问过达神,,,并不理解,,,继续思考,,,后来明白是为了找到所有序列中出现的数的最大值,这样才能建树啊,,,然后得出结论:我太傻以至于马上就要滚粗了,,,TAT

    最后向iwtwiioi寻求帮助,知道自己错误的原因是数组开的太小了,,

    达神也帮我开大过,不过貌似太大炸了导致每次都是TLE或WA,,

    还是得注意细节啊,这道题一个晚上才写出了模板,我果然太弱了。

    #include<cstdio>
    #include<algorithm>
    #define lowbit(x) (x&-x)
    #define read(x) x=getint()
    #define for1(i,a,n) for(int i=(a);i<=(n);++i)
    using namespace std;
    const int N=10010;
    inline const int getint(){char c=getchar();int k=1,r=0;for(;c<'0'||c>'9';c=getchar())if(c=='-')k=-1;for(;c>='0'&&c<='9';c=getchar())r=r*10+c-'0';return k*r;}
    struct node{int l,r,s;}T[N*300];
    int n,m,cl,cr,tot=0,num=0,cnt=0,ans[N<<1],root[N],a[N],L[N],R[N],QL[N],QR[N],K[N];
    inline void update(const int &l,const int &r,int &pos,const int &k,const int &sz){
        T[++tot]=T[pos]; pos=tot; T[pos].s+=sz;
        if (l==r) return; int mid=(l+r)>>1;
        if (k<=mid) update(l,mid,T[pos].l,k,sz); else update(mid+1,r,T[pos].r,k,sz);
    }
    inline void addd(int x,const int &k,const int &sz){for(;x<=n;x+=lowbit(x)) update(1,num,root[x],k,sz);}
    inline int query(const int &l,const int &r,const int &k){
        if (l==r) return l;
        int suml=0,sumr=0;
        for1(i,1,cl) suml+=T[T[L[i]].l].s;
        for1(i,1,cr) sumr+=T[T[R[i]].l].s;
        int mid=(l+r)>>1;
        if (k<=sumr-suml){
            for1(i,1,cl) L[i]=T[L[i]].l;
            for1(i,1,cr) R[i]=T[R[i]].l;
            return query(l,mid,k);
        }else{
            for1(i,1,cl) L[i]=T[L[i]].r;
            for1(i,1,cr) R[i]=T[R[i]].r;
            return query(mid+1,r,k-sumr+suml);
        }
    }
    inline int getans(int l,int r,const int &k){
        for(cl=0;l>0;l-=lowbit(l)) L[++cl]=root[l];
        for(cr=0;r>0;r-=lowbit(r)) R[++cr]=root[r];
        return query(1,num,k);
    }
    int main(){
        read(n); read(m); char c;
        for1(i,1,n) read(a[i]),ans[++cnt]=a[i];
        for1(i,1,m){
            for(c=getchar();c<'A'||c>'Z';c=getchar());
            read(QL[i]); read(QR[i]);
            if (c=='Q') read(K[i]);
            else ans[++cnt]=QR[i];
        }sort(ans+1,ans+cnt+1);
        ans[cnt+1]=1E9+10;
        for1(i,1,cnt) if (ans[i]!=ans[i+1]) ans[++num]=ans[i];
        for1(i,1,n) a[i]=lower_bound(ans+1,ans+num+1,a[i])-ans;
        for1(i,1,n) addd(i,a[i],1);
        for1(i,1,m){
            if (K[i]) printf("%d
    ",ans[getans(QL[i]-1,QR[i],K[i])]);
            else{
                addd(QL[i],a[QL[i]],-1);
                a[QL[i]]=lower_bound(ans+1,ans+num+1,QR[i])-ans;
                addd(QL[i],a[QL[i]],1);
            }
        }return 0;
    }
    

    然后就可以了。这是DaD3zZ几年前就随手虐的东西,本蒟蒻还得继续努力呀~~~

  • 相关阅读:
    MP3文件格式解析
    各种流媒体服务器的架设(一)
    fread函数和fwrite函数
    [转]C#算法 一对小兔子一年后长成大兔子;一对大兔子每半年生一对小兔子。大兔子的繁殖期为4年,兔子的寿命是6年。假定第一年年初投放了一对小兔子,试编程计算,第n年末总共会有多少对兔子
    C#算法 质因数 最大公约数与最小公倍数
    数据库删除语句 Drop/Delete/Truncate比较
    [转]C# 截取指定长度的中英文混合字符串的算法
    C#算法 母牛从第4年起每年生一头小母牛,并且母牛不会死
    C#算法 有一个母羊,第2年和第4年可以生一头小母羊,在第5年死去,小母羊在它出生的第2年和第4年生小母羊,第5年死去
    C#算法 最值/平均
  • 原文地址:https://www.cnblogs.com/abclzr/p/5223387.html
Copyright © 2011-2022 走看看