Evanyou Blog 彩带

洛谷P3919 【模板】可持久化数组 [主席树]

  题目传送门

可持久化数组

题目描述

如题,你需要维护这样的一个长度为 $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\n",T.quary(root[pre],1,n,pos));
            root[i]=root[pre];
        }
    }
    return 0;
}

 

posted @ 2018-08-05 22:03  HolseLee  阅读(182)  评论(0编辑  收藏  举报