• [BZOJ 1901] Dynamic Rankings


    Link:

    BZOJ 1901 传送门

    Solution:

    带修改主席树的模板题

    对于静态区间第$k$大直接上主席树就行了

    但加上修改后会发现修改时复杂度不满足要求了:

    去掉/增加第$i$位上的值时要更新$i...n$间所有的主席树,使得单次修改的复杂度达到$n*log(n)$

    可以将原来的主席树看成前缀数组

    求某一段时尚可直接差分,但涉及到修改时就要改动$O(n)$级别的节点了

    这时想到优化前缀和问题的树状数组

    如果将原来的每一棵主席树看作树状数组上的点并利用$lowbit()$修改/求值

    这样就能每次改动$log(n)$棵主席树,从而将复杂度降到$log(n)^2$

    实现中先离散化,对于每一次修改先去掉删除原值,再添加新值就好啦

    注意修改时要先记录所有需要的节点并一起移动,对于$k$大问题无法单独计算

    Tip:

    1、此时每棵线段树已经不再具有主席树的性质了:每次修改在前者基础上增加一条链

    其实现在每棵线段树就是在自己原基础上修改,准确地说就是树状数组套动态开点权值线段树

    2、好像此类动态开点线段树的空间复杂度我不太会算……

    此题好像$O(n*log(n))$就够用了……

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    const int MAXN=10005;
    char s[20];
    struct Query{int i,j,k;}q[MAXN];
    //内存开大,好像这题n*log(n)就够了
    struct PrTree{int ls,rs,cnt;}seg[3000005];
    int n,m,dat[MAXN],rt[MAXN],L[30],R[30],dsp[MAXN<<1],tot,totl,totr,cnt;
    inline int lowbit(int x){return x&(-x);}
    //PrTree
    void Update(int &cur,int pos,int val,int l,int r)
    {
        if(!cur) cur=++cnt;
        seg[cur].cnt+=val;
        if(l==r) return;int mid=(l+r)>>1;
        if(pos<=mid) Update(seg[cur].ls,pos,val,l,mid);
        else Update(seg[cur].rs,pos,val,mid+1,r);
    }
    
    int Query(int k,int l,int r)
    {
        if(l==r) return l;
        int sum=0,mid=(l+r)>>1;
        for(int i=1;i<=totl;i++) sum-=seg[seg[L[i]].ls].cnt;
        for(int i=1;i<=totr;i++) sum+=seg[seg[R[i]].ls].cnt;
        if(sum>=k)
        {
            for(int i=1;i<=totl;i++) L[i]=seg[L[i]].ls;
            for(int i=1;i<=totr;i++) R[i]=seg[R[i]].ls;
            return Query(k,l,mid);
        }
        else
        {
            for(int i=1;i<=totl;i++) L[i]=seg[L[i]].rs;
            for(int i=1;i<=totr;i++) R[i]=seg[R[i]].rs;
            return Query(k-sum,mid+1,r);
        }
    }
    //BIT
    void upd(int x,int val)
    {
        int pos=lower_bound(dsp+1,dsp+tot+1,dat[x])-dsp;
        for(int i=x;i<=n;i+=lowbit(i))
            Update(rt[i],pos,val,1,tot);
    }
    
    int qry(int l,int r,int k)
    {
        totl=totr=0;
        for(int i=l-1;i;i-=lowbit(i)) L[++totl]=rt[i];
        for(int i=r;i;i-=lowbit(i)) R[++totr]=rt[i];
        return dsp[Query(k,1,tot)];
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&dat[i]),dsp[++tot]=dat[i];
        for(int i=1;i<=m;i++)
        {
            scanf("%s%d%d",s,&q[i].i,&q[i].j);
            if(s[0]=='Q') scanf("%d",&q[i].k);
            else dsp[++tot]=q[i].j;
        }
        sort(dsp+1,dsp+tot+1);
        tot=unique(dsp+1,dsp+tot+1)-dsp-1;
        
        for(int i=1;i<=n;i++) upd(i,1);
        for(int i=1;i<=m;i++)
        {
            if(q[i].k) printf("%d
    ",qry(q[i].i,q[i].j,q[i].k));
            else upd(q[i].i,-1),dat[q[i].i]=q[i].j,upd(q[i].i,1);
        }
        return 0;
    }
  • 相关阅读:
    设计模式
    《黑马程序员》类和对象(Objective
    《黑马程序员》认识OC的第一个程序(Objective-c)
    《黑马程序员》 字符串 (C语言)
    《黑马程序员》 关键字---typedef (C语言)
    《黑马程序员》预处理指令(宏定义、条件编译、文件包含)(C语言)
    《黑马程序员》 结构体struct (C语言)
    《黑马程序员》局部变量与全局变量 (C语言)
    《黑马程序员》 ★指针练习★ (C语言)
    《黑马程序验》数组与函数(C语言)
  • 原文地址:https://www.cnblogs.com/newera/p/9357282.html
Copyright © 2020-2023  润新知