zoukankan      html  css  js  c++  java
  • 可持久化数组(主席树)

    模板代码:

    #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
  • 相关阅读:
    out/host/linuxx86/obj/EXECUTABLES/aapt_intermediates/aapt 64 32 操作系统
    linux 查看路由器 电脑主机 端口号 占用
    linux proc进程 pid stat statm status id 目录 解析 内存使用
    linux vim 设置大全详解
    ubuntu subclipse svn no libsvnjavahl1 in java.library.path no svnjavahl1 in java.library.path no s
    win7 安装 ubuntu 双系统 详解 easybcd 工具 不能进入 ubuntu 界面
    Atitit.json xml 序列化循环引用解决方案json
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    Atitit.跨语言  文件夹与文件的io操作集合  草案
    Atitit.atijson 类库的新特性设计与实现 v3 q31
  • 原文地址:https://www.cnblogs.com/guoshaoyang/p/10924416.html
Copyright © 2011-2022 走看看