• 可持久化数组(主席树)


    模板代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    #define mid ((l+r)>>1)
    const int INF=1e9+7,MAXNODE=24e6+7,MAXN=1e6+7;
    int N,M,tmp[MAXN],rt[MAXN];
    int val[MAXNODE],lson[MAXNODE],rson[MAXNODE],sz;
    void init(int &x,int l,int r){
        x=++sz;
        if(l==r){
            val[x]=tmp[l];
            return;
        }
        init(lson[x],l,mid);
        init(rson[x],mid+1,r);
    }
    void modify(int &x,int l,int r,int p,int q,int v){
        x=++sz;
        if(l==r){
            val[x]=v;
            return;
        }
        lson[x]=lson[p];
        rson[x]=rson[p];
        val[x]=val[p];
        if(q<=mid)
            modify(lson[x],l,mid,lson[p],q,v);
        else
            modify(rson[x],mid+1,r,rson[p],q,v);
    }
    int query(int x,int l,int r,int q){
        if(l==r)
            return val[x];
        if(q<=mid)
            return query(lson[x],l,mid,q);
        return query(rson[x],mid+1,r,q);
    }
    int main(){
        scanf("%d%d",&N,&M);
        for(int i=1;i<=N;i++)
            scanf("%d",tmp+i);
        init(rt[0],1,N);
        for(int i=1;i<=M;i++){
            int edit/*edition*/,oper,loc/*location*/,v/*value*/;
            scanf("%d%d%d",&edit,&oper,&loc);
            if(oper==1){
                scanf("%d",&v);
                modify(rt[i],1,N,rt[edit],loc,v);
            }else{
                printf("%d
    ",query(rt[edit],1,N,loc));
                rt[i]=rt[edit];
            }
        }
        return 0;
    }
    View Code

    原题链接题面:

      

     

     

     可持久化数组实现

     1.结构主席树

     2.思想:对于每一个版本的数组建一棵线段树,因为相邻版本差异为一个数字,所以单次修改时间空间复杂度均为O(logN)

     3.实现

    • 先定义一些数组(主席树的常规成员):
    1. const int MAXN数字个数,MAXNODE节点个数(2*N+NlogN)
      int N数字个数,M查询个数,tmp[MAXN]读入数值暂存数组,rt[MAXN]每个版本的线段树的根;
      int val[MAXNODE]线段树值,lson[MAXNODE]左儿子,rson[MAXNODE]右儿子,sz节点栈顶;
    • 初始化
    1. 读入并建树,将版本为0的线段树为初始树根
    2. scanf("%d%d",&N,&M);
      for(int i=1;i<=N;i++)
          scanf("%d",tmp+i);
      init(rt[0],1,N);

       按照动态开点线段树常规方法建树

      void init(int &x,int l,int r){
          x=++sz;
          if(l==r){
              val[x]=tmp[l];
              return;
          }
          init(lson[x],l,mid);
          init(rson[x],mid+1,r);
      }
    • 更新
    • void modify(int &x当前节点下标,int l,int r,int p上一个版本,int q要赋值的位置,int v值){
          x=++sz;
          if(l==r){找到节点,赋值并退出
              val[x]=v;
              return;
          }
          lson[x]=lson[p];复制上一个版本的节点信息
          rson[x]=rson[p];
          val[x]=val[p];
          if(q<=mid)按照动态开点线段树遍历
              modify(lson[x],l,mid,lson[p],q,v);
          else
              modify(rson[x],mid+1,r,rson[p],q,v);
      }
    • 查询:常规线段树查询
    • int query(int x当前点下标,int l,int r,int q查询位置){
          if(l==r)
              return val[x];
          if(q<=mid)
              return query(lson[x],l,mid,q);
          return query(rson[x],mid+1,r,q);
      }

     完整代码: 

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long LL;
     4 #define mid ((l+r)>>1)
     5 const int INF=1e9+7,MAXNODE=24e6+7,MAXN=1e6+7;
     6 int N,M,tmp[MAXN],rt[MAXN];
     7 int val[MAXNODE],lson[MAXNODE],rson[MAXNODE],sz;
     8 void init(int &x,int l,int r){
     9     x=++sz;
    10     if(l==r){
    11         val[x]=tmp[l];
    12         return;
    13     }
    14     init(lson[x],l,mid);
    15     init(rson[x],mid+1,r);
    16 }
    17 void modify(int &x,int l,int r,int p,int q,int v){
    18     x=++sz;
    19     if(l==r){
    20         val[x]=v;
    21         return;
    22     }
    23     lson[x]=lson[p];
    24     rson[x]=rson[p];
    25     val[x]=val[p];
    26     if(q<=mid)
    27         modify(lson[x],l,mid,lson[p],q,v);
    28     else
    29         modify(rson[x],mid+1,r,rson[p],q,v);
    30 }
    31 int query(int x,int l,int r,int q){
    32     if(l==r)
    33         return val[x];
    34     if(q<=mid)
    35         return query(lson[x],l,mid,q);
    36     return query(rson[x],mid+1,r,q);
    37 }
    38 int main(){
    39     scanf("%d%d",&N,&M);
    40     for(int i=1;i<=N;i++)
    41         scanf("%d",tmp+i);
    42     init(rt[0],1,N);
    43     for(int i=1;i<=M;i++){
    44         int edit/*edition*/,oper,loc/*location*/,v/*value*/;
    45         scanf("%d%d%d",&edit,&oper,&loc);
    46         if(oper==1){
    47             scanf("%d",&v);
    48             modify(rt[i],1,N,rt[edit],loc,v);
    49         }else{
    50             printf("%d
    ",query(rt[edit],1,N,loc));
    51             rt[i]=rt[edit];
    52         }
    53     }
    54     return 0;
    55 }
    View Code
  • 相关阅读:
    堆和栈的区别!
    产品经理和程序员的爱恨情仇
    字符串MD5加密运算
    事件驱动模型。。。。有时间弄
    Apache服务器httpd.exe进程占用cpu超过50%的解决方法
    ZigBee Xbee S2通讯设置
    pipe-filter 真难找啊
    javacomm64位用不了,可以使用RXTXcomm for x64
    导入 sun.net.TelnetInputStream; 报错
    linux下gedit读取txt乱码解决办法
  • 原文地址:https://www.cnblogs.com/guoshaoyang/p/10924416.html
Copyright © 2020-2023  润新知