洛谷 P3919 【模板】可持久化线段树 1(可持久化数组)

维护长度为 N 的数组,可支持如下操作:

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

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

  • 可持久化线段树(主席树)
#include<cstdio>
#include<iostream>
#define MAXN 1000010
using namespace std;
int n,m,a[MAXN],rt[MAXN],r,t,p,v,tot;
struct Node{
    int l,r,v;
}tree[MAXN*20];
int build(int k,int l,int r){
    k=++tot;
    if(l==r){
        tree[k].v=a[l];
        return tot;
    }
    int m=(l+r)/2;
    tree[k].l=build(tree[k].l,l,m);
    tree[k].r=build(tree[k].r,m+1,r);
    return k;
}
int clone(int k){
    tree[++tot]=tree[k];
    return tot;
}
int update(int k,int l,int r,int p,int v){
    k=clone(k);
    if(l==r)tree[k].v=v;
    else{
        int m=(l+r)/2;
        if(p<=m)tree[k].l=update(tree[k].l,l,m,p,v);
        else tree[k].r=update(tree[k].r,m+1,r,p,v);
    }
    return k;
}
int query(int k,int l,int r,int p){
    if(l==r)return tree[k].v;
    else{
        int m=(l+r)/2;
        if(p<=m)return query(tree[k].l,l,m,p);
        else return query(tree[k].r,m+1,r,p);
    }
}
int main(){
#ifdef WINE
    freopen("data.in","r",stdin);
#endif
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    rt[0]=build(0,1,n);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&r,&t,&p);
        if(t==1){ // 修改
            scanf("%d",&v);
            rt[i]=update(rt[r],1,n,p,v);
        }else{
            printf("%d\n",query(rt[r],1,n,p));
            rt[i]=rt[r];
        }
    }
}

posted @ 2020-08-19 23:05  winechord  阅读(90)  评论(0编辑  收藏  举报