BZOJ.1901.Dynamic Rankings(树状数组套主席树(动态主席树))

题目链接 BZOJ
洛谷

区间第k小,我们可以想到主席树。然而这是静态的,怎么支持修改?
静态的主席树是利用前缀和+差分来求解的,那么对于每个位置上的每棵树看做一个点,拿树状数组更新。
还是树状数组的过程,区间加时,每到一个位置在这棵主席树中插入这个数。
查询时,将所有询问要访问到的主席树存下来,delta为所有存下的树的和的差值;改变节点时所有的主席树访问节点都变。
每次树状数组会访问logn棵树,每棵树改变logn个点。时间空间复杂度都为 \(O(nlog^2n)\).

线段树套平衡树见这.
整体二分见这.

//27068kb   364ms
#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
#define lb(x) (x)&-(x)
const int N=1e4+5,S=N*220,MAXIN=1e5;

int n,Q,A[N],cnt,ref[N<<1];
char IN[MAXIN],*SS=IN,*TT=IN;
struct Operation{ //离线离散化 
    int l,r,K;//l=0:Modify r:pos K:val
    Operation() {}
    Operation(int l,int r,int k):l(l),r(r),K(k) {}
}q[N];
inline int read()
{
    int now=0,f=1;register char c=gc();
    for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now*f;
}
namespace T
{
    #define lson son[rt][0]
    #define rson son[rt][1]

    int tot,son[S][2],sz[S],root[N],totl,totr,ql[N],qr[N];
    void Insert(int &rt,int l,int r,int p,int v)
    {
        if(!rt) rt=++tot;
        sz[rt]+=v;//既然直接在自己这棵树上改,不需要再复制很多重复节点。
        if(l<r){
            int m=l+r>>1;
            if(p<=m) Insert(lson,l,m,p,v);
            else Insert(rson,m+1,r,p,v);
        }
    }
    void Modify(int p,int v,int delta){
        while(p<=n)
            Insert(root[p],1,cnt,v,delta),p+=lb(p);
    }
    int Query(int l,int r,int k)
    {
        if(l==r) return ref[l];
        int delta=0;
        for(int i=1; i<=totl; ++i) delta-=sz[son[ql[i]][0]];
        for(int i=1; i<=totr; ++i) delta+=sz[son[qr[i]][0]];
        if(delta>=k){
            for(int i=1; i<=totl; ++i) ql[i]=son[ql[i]][0];
            for(int i=1; i<=totr; ++i) qr[i]=son[qr[i]][0];
            return Query(l,l+r>>1,k);
        }
        else{
            for(int i=1; i<=totl; ++i) ql[i]=son[ql[i]][1];
            for(int i=1; i<=totr; ++i) qr[i]=son[qr[i]][1];
            return Query((l+r>>1)+1,r,k-delta);
        }
    }
    int Kth(int l,int r,int k)
    {//别忘l-1.
        totl=totr=0;
        for(--l; l; l^=lb(l)) ql[++totl]=root[l];//存根。
        for(; r; r^=lb(r)) qr[++totr]=root[r];
        return Query(1,cnt,k);
    }
}
inline char Get(){
    char c=gc();while(c!='Q'&&c!='C') c=gc();
    return c;
}
int Find(int x)
{
    int l=1,r=cnt,mid;
    while(l<r)
        if(ref[mid=l+r>>1]<x) l=mid+1;
        else r=mid;
    return l;
}

int main()
{
    n=read(),Q=read();
    for(int i=1; i<=n; ++i) ref[i]=A[i]=read();
    int t=n;
    for(int l,r,k,i=1; i<=Q; ++i)
        if(Get()=='Q') l=read(),r=read(),k=read(), q[i]=Operation(l,r,k);
        else r=read(),k=read(), q[i]=Operation(0,r,k),ref[++t]=k;

    std::sort(ref+1,ref+1+t), cnt=1;
    for(int i=2; i<=t; ++i)
        if(ref[i]!=ref[i-1]) ref[++cnt]=ref[i];

    for(int i=1; i<=n; ++i) T::Modify(i,A[i]=Find(A[i]),1);
    for(int i=1; i<=Q; ++i)
        if(!q[i].l) T::Modify(q[i].r,A[q[i].r],-1), T::Modify(q[i].r,A[q[i].r]=Find(q[i].K),1);
        else printf("%d\n",T::Kth(q[i].l,q[i].r,q[i].K));
    return 0;
}

转载于:https://www.cnblogs.com/SovietPower/p/8653956.html

Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值