zoukankan      html  css  js  c++  java
  • 主席树简明教程

    在线段树的实际应用中,我们经常要访问线段树的历史版本。

    这时候,我们就需要一种新的数据结构:主席树(别问我为什么叫主席树,去问主席)。

     

    由于之前写了半天的消失了,那我就写个简洁点的。 

     

    为了保存线段树的历史版本,我们可以每修改一次就复制整棵线段树。

    但是这样做空间和时间都承受不下,然后我们会发现每一次修改事实上只影响了一部分节点。

    那么我们对于每次修改,就可以只复制一遍影响到的节点并且进行修改,其他的节点共用。

    每次都会新建一个根,记录每个版本的线段树的根节点地址就可以找到这个版本。

    如图:

    图就建成这样,然后要访问历史版本的时候找到那个根就好了。

    最终对于一个有n个数的序列,会建立n棵共用部分节点的线段树,编号为i的树中有序列中前i个数的信息。

    那么假如要询问一个区间的某些信息,只要用前缀和的思想两端相减即可得到(权值线段树)。

    //洛谷P3834主席树模板的代码
    int build(int L,int R){
        int num=cnt++; sum[num]=0; if(L>=R)return num;
        lch[num]=build(L,mid); rch[num]=build(mid+1,R);
        return num;
    }//最开始的表示前0个数的线段树
    
    int insert(int pre,int L,int R,int x){
        int num=cnt++;
        sum[num]=sum[pre]+1;if(L>=R)return num;
        lch[num]=lch[pre],rch[num]=rch[pre];
        if(x<=mid)lch[num]=insert(lch[num],L,mid,x);
        else rch[num]=insert(rch[num],mid+1,R,x);
        return num;
    }//这里使用权值线段树,在前一棵线段树的基础上插入一个x
    
    int query(int u,int v,int L,int R,int k){
        if(L>=R)return L;
        int cnt=sum[lch[v]]-sum[lch[u]];
        if(cnt<k)return query(rch[u],rch[v],mid+1,R,k-cnt);
        else return query(lch[u],lch[v],L,mid,k);
    }
    
    void init(){
        n=read(),q=read();
        for(int i=1;i<=n;i++)a[i]=b[i]=read();
        sort(b+1,b+n+1); m=unique(b+1,b+n+1)-b-1;//排序去重
        rt[0]=build(1,m);
        for(int i=1;i<=n;i++){
            int temp=lower_bound(b+1,b+m+1,a[i])-b;
            rt[i]=insert(rt[i-1],1,m,temp);//记录每一棵线段树的根节点编号
        }
        return ;
    }
    
    void work(){
        for(int i=1;i<=q;i++){
            int opl=read(),opr=read(),k=read();
            int u=query(rt[opl-1],rt[opr],1,m,k);
            write(b[u]),putchar('
    ');
        }
        return ;
    }
    

      

    总结一下,这个数据结构就是靠指针来维持,主要思想就是只复制并修改一次操作影响到的的节点。

    对于其他节点和指针,都不进行修改,不同版本之间可能会共用一些节点,从而减少时空复杂度。

  • 相关阅读:
    如何在页面上输出html标签:符号实体【转】
    js sort方法根据数组中对象的某一个属性值进行排序【转】
    原生js判断某个元素是否有指定的class名的几种方法【转】
    js支持的编码转换方法【转】
    windows mysql提示:1045 access denied for user 'root'@'localhost' using password yes 解决方案【转】
    PHP 生成随机数rand()和mt_rand()的区别【转】
    php中var关键字用法【转】
    2020软件工程个人作业06——软件工程实践总结作业
    旺宝的家——事后诸葛亮
    旺宝的家—冲刺总结
  • 原文地址:https://www.cnblogs.com/gdc-destinies/p/8377412.html
Copyright © 2011-2022 走看看