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 ;
    }
    

      

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

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

  • 相关阅读:
    Matlab smooth函数原理
    Pandas中的高级索引loc、iloc、ix精简概括
    QT常见错误:"multiple definition of xxx"
    Github术语解释
    数据反转 LSB
    LSB最低有效位和MSB最高有效位
    Modbus通信CRC16校验程序
    CRC16常见几个标准的算法及C语言实现
    DB9 公头母头引脚定义及连接
    hdu 2577 How to Type(dp)
  • 原文地址:https://www.cnblogs.com/gdc-destinies/p/8377412.html
Copyright © 2011-2022 走看看