zoukankan      html  css  js  c++  java
  • 洛谷 P3919 【模板】可持久化数组(可持久化线段树/平衡树)

    当然是可以用可持久化线段树/平衡树做的。不过这里记一下一种奇怪的方法:http://blog.csdn.net/kscla/article/details/53586880

    如果用线段树来维护的话,线段树上非叶子节点的节点都是没有用的,因为并不需要它们记录值。因此可以建一棵二叉树,每一个节点表示原数组上一个位置,节点1表示数组的第一个元素,之后的节点满足:设节点i表示数组的第k个元素,则节点i的左子节点表示数组的第k*2个元素,右子节点表示数组的第k*2+1个元素。

    要找到某个节点时,需要用到二进制表示。比如要找到表示原数组上第6个元素的节点,6的二进制表示是110,去掉开头的1不看,那么表示从根节点先向右走(根据第二位的1),再向左走(根据第三位的0),就到了该节点。

    这样子能降低常数,打起来也很方便(不过感觉有点不自然?)

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define LX (pos<<1)
     4 #define RX (pos<<1|1)
     5 using namespace std;
     6 int n,m,a[1000100],root[1000100],mem,ch[20000000][2],dat[20000000];
     7 bool g[30];
     8 int glen;
     9 void build(int pos,int& num)
    10 {
    11     num=++mem;
    12     dat[num]=a[pos];
    13     if(LX<=n)    build(LX,ch[num][0]);
    14     if(RX<=n)    build(RX,ch[num][1]);
    15 }
    16 int query(int posx,int num)
    17 {
    18     for(glen=0;posx!=1;posx>>=1)    g[++glen]=(posx&1);
    19     for(int i=glen;i>=1;--i)    num=ch[num][g[i]];
    20     return dat[num];
    21 }
    22 int x;
    23 void upd_x(int dep,int& num)
    24 {
    25     int t=num;num=++mem;ch[num][0]=ch[t][0];ch[num][1]=ch[t][1];dat[num]=dat[t];
    26     if(!dep)    {dat[num]=x;return;}
    27     upd_x(dep-1,ch[num][g[dep]]);
    28 }
    29 void upd(int posx,int& num)
    30 {
    31     for(glen=0;posx!=1;posx>>=1)    g[++glen]=(posx&1);
    32     upd_x(glen,num);
    33 }
    34 int main()
    35 {
    36     int i,ver,idx,pos;
    37     scanf("%d%d",&n,&m);
    38     for(i=1;i<=n;i++)    scanf("%d",&a[i]);
    39     build(1,root[0]);
    40     //for(i=1;i<=n;i++)    printf("a%d
    ",query(i,root[0]));
    41     for(i=1;i<=m;i++)
    42     {
    43         scanf("%d%d%d",&ver,&idx,&pos);
    44         if(idx==1)
    45         {
    46             scanf("%d",&x);
    47             root[i]=root[ver];upd(pos,root[i]);
    48         }
    49         else
    50         {
    51             root[i]=root[ver];printf("%d
    ",query(pos,root[i]));
    52         }
    53     }
    54     return 0;
    55 }

    可以把更新也写成非递归。。。

    void upd(int posx,int& num)
    {
        int t,*t2=&num;for(glen=0;posx!=1;posx>>=1)    g[++glen]=(posx&1);
        for(int dep=glen;dep;--dep)
        {
            t=*t2;*t2=mem++;ch[*t2][0]=ch[t][0];ch[*t2][1]=ch[t][1];dat[*t2]=dat[t];
            t2=&ch[*t2][g[dep]];
        }
        t=*t2;*t2=mem++;ch[*t2][0]=ch[t][0];ch[*t2][1]=ch[t][1];dat[*t2]=dat[t];
        dat[*t2]=x;
    }
  • 相关阅读:
    [转]HD钱包的助记词与密钥生成原理
    [转]简单科普私钥、地址、助记词、Keystore的区别
    [转]Sequelize 中文API文档-4. 查询与原始查询
    [转]Node.JS使用Sequelize操作MySQL
    [转]OmniLayer / omnicore API 中文版
    [转]usdt omnicore testnet 测试网络
    [转]USDT与omniCore钱包
    [转]BTC RPC API GetTransaction
    [转]比特币测试链——Testnet介绍
    [转]BTC手续费计算,如何设置手续费
  • 原文地址:https://www.cnblogs.com/hehe54321/p/8527833.html
Copyright © 2011-2022 走看看