• 可持久化专题(二)——可持久化数组的实现


    前言

    呃,首先声明,看这篇博客前,最好先去学一学主席树,毕竟可持久化数组的实现是完全基于主席树的(那些乱七八糟的玄学算法请走开)。

    顺便吐槽一句,可持久化数组这个名字听起来真的很智障。

    简介

    可持久化数组支持单点修改单点查询

    .单点修改单点查询这种东西不是直接数组就能解决了吗?干嘛要可持久化?

    因为要用到历史版本啊!

    基本思路

    思路1:我们可以考虑对每一个版本开一个数组,这就是最暴力的打法了,这样显然会MLE+TLE

    思路2:高级一点,我们可以考虑对每一个版本建一棵线段树,查询时在线段树上查询,这样的效率还不如一个暴力数组,结果会MLE+TLE得更惨

    思路3:虽然思路2会炸飞,但是,它显然比思路1更容易优化。看到一群线段树,我们很容易想到用可持久化线段树——主席树来优化它。

    具体实现

    在这里,主席树的作用就不是查询区间第(k)大了,而是在每一个叶子节点上记录当前版本这一位上的值

    如果你主席树打得够熟练,这就是一道水题了,直接上代码吧:(还是洛谷上的一道板子题

    #include<bits/stdc++.h>
    #define max(x,y) ((x)>(y)?(x):(y))
    #define min(x,y) ((x)<(y)?(x):(y))
    #define LL long long
    #define swap(x,y) (x^=y,y^=x,x^=y)
    #define tc() (A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++)
    #define pc(ch) (pp_<100000?pp[pp_++]=(ch):(fwrite(pp,1,100000,stdout),pp[(pp_=0)++]=(ch)))
    #define N 1000000 
    int pp_=0;char ff[100000],*A=ff,*B=ff,pp[100000];
    using namespace std;
    int n,Q,tot=0,rt[N+5],a[N+5];
    struct Chairman_Tree
    {
        int Son[2],Val;
    }node[N*20];
    inline void read(int &x)
    {
        x=0;int f=1;char ch;
        while(!isdigit(ch=tc())) f=ch^'-'?1:-1;
        while(x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
        x*=f;
    }
    inline void write(int x)
    {
        if(x<0) pc('-'),x=-x;
        if(x>9) write(x/10);
        pc(x%10+'0');
    }
    inline void Build(int &rt,int l,int r)//初始的建树,在这道题中,除了动态开点以外与线段树完全一样
    {
        rt=++tot;
        int mid=l+r>>1;
        if(!(l^r)) {node[rt].Val=a[l];return;}
        Build(node[rt].Son[0],l,mid),Build(node[rt].Son[1],mid+1,r);
    }
    inline void NewPoint(int &rt,int lst,int l,int r,int x,int val)//新建一个版本
    {
        node[rt=++tot]=node[lst];
        int mid=l+r>>1;
        if(!(l^r)) {node[rt].Val=val;return;}
        if(x<=mid) NewPoint(node[rt].Son[0],node[lst].Son[0],l,mid,x,val);
        else NewPoint(node[rt].Son[1],node[lst].Son[1],mid+1,r,x,val);
    }
    inline int Query(int rt,int l,int r,int x)//询问某一版本某一位上的值
    {
        int mid=l+r>>1;
        if(!(l^r)) return node[rt].Val;
        if(x<=mid) return Query(node[rt].Son[0],l,mid,x);
    	else return Query(node[rt].Son[1],mid+1,r,x); 
    }
    int main()
    {
        register int i;
        for(read(n),read(Q),i=1;i<=n;++i) read(a[i]);
        for(Build(rt[0],i=1,n);i<=Q;++i)//建树,然后进行操作
        {
            int v,op,x,val;
            read(v),read(op),read(x);
    		if(op^2) read(val),NewPoint(rt[i],rt[v],1,n,x,val);//新建一个版本
    		else write(Query(rt[i]=rt[v],1,n,x)),pc('
    ');//输出答案,并复制这个版本
        }
        return fwrite(pp,1,pp_,stdout),0;
    }
    
  • 相关阅读:
    羊车门悖论
    python--程序语言中的我行我素者
    最大流isap
    约瑟夫环问题
    CF 916 一言题解
    ZJOI2006 书架
    板子
    windows激活流程
    Ant Design 坑
    js+jQuery判断一个点是否在多边形中
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/PersistentArray.html
Copyright © 2020-2023  润新知