• Evanyou Blog 彩带


      题目传送门

    可持久化数组

    题目描述

    如题,你需要维护这样的一个长度为 $N$ 的数组,支持如下几种操作

    1. 在某个历史版本上修改某一个位置上的值

    2. 访问某个历史版本上的某一位置的值

    此外,每进行一次操作(对于操作2,即为生成一个完全一样的版本,不作任何改动),就会生成一个新的版本。版本编号即为当前操作的编号(从1开始编号,版本0表示初始状态数组)

    输入输出格式

    输入格式:

     

    输入的第一行包含两个正整数 $N, M$, 分别表示数组的长度和操作的个数。

    第二行包含 $N$ 个整数,依次为初始状态下数组各位的值(依次为 $a_i$, $1 leq i leq N$ )。

    接下来 $M$ 行每行包含3或4个整数,代表两种操作之一( $i$ 为基于的历史版本号):

    1. 对于操作1,格式为 $v_i 1 {loc}_i {value}_i$ ,即为在版本 $v_i$ 的基础上,将 $a_{{loc}_i}$ 修改为 ${value}_i$​

    2. 对于操作2,格式为 $v_i 2 {loc}_i$ ,即访问版本 $v_i$ 中的 $a_{{loc}_i}$ 的值

     

    输出格式:

     

    输出包含若干行,依次为每个操作2的结果。

     

    输入输出样例

    输入样例#1: 
    5 10
    59 46 14 87 41
    0 2 1
    0 1 1 14
    0 1 1 57
    0 1 1 88
    4 2 4
    0 2 5
    0 2 4
    4 2 1
    2 2 2
    1 1 5 91
    输出样例#1: 
    59
    87
    41
    87
    88
    46

    说明

    数据规模:

    对于30%的数据: $1 leq N, M leq {10}^3$

    对于50%的数据: $1 leq N, M leq {10}^4$

    对于70%的数据: $1 leq N, M leq {10}^5$

    对于100%的数据: $1 leq N, M leq {10}^6, 1 leq {loc}_i leq N, 0 leq v_i < i, -{10}^9 leq a_i, {value}_i leq {10}^9$

    经测试,正常常数的可持久化数组可以通过,请各位放心

    数据略微凶残,请注意常数不要过大

    另,此题I/O量较大,如果实在TLE请注意I/O优化

    询问生成的版本是指你访问的那个版本的复制


      分析:

      可持久化数据结构的一个好板子,这里蒟蒻用的是可持久化线段树(因为只会这个)

      每次操作的时候,复制询问的前一个状态的路径即可。另外询问操作直接把那一次的root修改为当前询问的历史版本的root。

      Code:

    //It is made by HolseLee on 5th Aug 2018
    //Luogu.org P3919
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<iostream>
    #include<iomanip>
    #include<algorithm>
    using namespace std;
    
    const int N=1e6+7;
    int n,m,root[N],a[N],cnt;
    struct node{
        int ls,rs,val;
    };
    struct Seg{
        node seg[N*20];
        
        inline void build(int &rt,int l,int r)
        {
            rt=++cnt;
            if(l==r){
                seg[rt].val=a[l];return;
            }
            int mid=(l+r)>>1;
            build(seg[rt].ls,l,mid);
            build(seg[rt].rs,mid+1,r);
        }
    
        inline void update(int &rt,int last,int l,int r,int pos,int v)
        {
            rt=++cnt;
            seg[rt].ls=seg[last].ls,seg[rt].rs=seg[last].rs;
            seg[rt].val=seg[last].val;
            if(l==r){
                seg[rt].val=v;return;
            }
            int mid=(l+r)>>1;
            if(pos<=mid)update(seg[rt].ls,seg[last].ls,l,mid,pos,v);
            else update(seg[rt].rs,seg[last].rs,mid+1,r,pos,v);
        }
    
        inline int quary(int rt,int l,int r,int pos)
        {
            if(l==r)return seg[rt].val;
            int mid=(l+r)>>1;
            if(pos<=mid)return quary(seg[rt].ls,l,mid,pos);
            else return quary(seg[rt].rs,mid+1,r,pos);
        }
    }T;
    
    inline int read()
    {
        char ch=getchar();int num=0;bool flag=false;
        while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}
        while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();}
        return flag?-num:num;
    }
    
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=n;++i)a[i]=read();
        T.build(root[0],1,n);
        int pre,pos,value,op;
        for(int i=1;i<=m;++i){
            pre=read();op=read();pos=read();
            if(op==1){
                T.update(root[i],root[pre],1,n,pos,read());
            }
            else {
                printf("%d
    ",T.quary(root[pre],1,n,pos));
                root[i]=root[pre];
            }
        }
        return 0;
    }
  • 相关阅读:
    Design and Analysis of Algorithms_Decrease-and-Conquer
    TCPL 札记
    谬论:64 = 65?
    二叉树内部顶点与外部顶点在数量上的关系
    Design and Analysis of Algorithms_Divide-and-Conquer
    LeetCode 36. Valid Sudoku
    LeetCode 58. Length of Last Word
    LeetCode 66. Plus One
    LeetCode 67. Add Binary
    LeetCode 70. Climbing Stairs
  • 原文地址:https://www.cnblogs.com/cytus/p/9427529.html
Copyright © 2020-2023  润新知