可持久化陣列

2022-08-21 17:30:10 字數 3172 閱讀 9685

update : 最後乙個點時間空間已經放大

標題即題意

有了可持久化陣列,便可以實現很多衍生的可持久化功能(例如:可持久化並查集)

如題,你需要維護這樣的乙個長度為 nn 的陣列,支援如下幾種操作

在某個歷史版本上修改某乙個位置上的值

訪問某個歷史版本上的某一位置的值

此外,每進行一次操作(對於操作2,即為生成乙個完全一樣的版本,不作任何改動),就會生成乙個新的版本。版本編號即為當前操作的編號(從1開始編號,版本0表示初始狀態陣列)

輸入格式:

輸入的第一行包含兩個正整數 n, mn,m, 分別表示陣列的長度和操作的個數。

第二行包含nn個整數,依次為初始狀態下陣列各位的值(依次為 a_iai​,1 \leq i \leq n1≤i≤n)。

接下來mm行每行包含3或4個整數,代表兩種操作之一(ii為基於的歷史版本號):

對於操作1,格式為v_i \ 1 \ _i \ _ivi​1loci​valuei​,即為在版本v_ivi​的基礎上,將 a__i}aloci​​修改為 _ivaluei​

對於操作2,格式為v_i \ 2 \ _ivi​2loci​,即訪問版本v_ivi​中的 a__i}aloci​​的值

輸出格式:

輸出包含若干行,依次為每個操作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

8741

8788

46

資料規模:

對於30%的資料:1 \leq n, m \leq ^31≤n,m≤103

對於50%的資料:1 \leq n, m \leq ^41≤n,m≤104

對於70%的資料:1 \leq n, m \leq ^51≤n,m≤105

對於100%的資料:1 \leq n, m \leq ^6, 1 \leq _i \leq n, 0 \leq v_i < i, -^9 \leq a_i, _i \leq ^91≤n,m≤106,1≤loci​≤n,0≤vi​思路1:樹上dfs離線操作

#include#define f(c)   for(int i=1;i<=c;i++)

using

namespace

std;

const

int maxn = 1000009

;int

head[maxn],n,m,cnt,a[maxn],ans[maxn];

struct edge[maxn];

struct nodeq[maxn];

bool

uuz[maxn];

int i()

void add(int x,int y)

void dfs(int x)

int main()

dfs(

0);f(m)if(uuz[i])printf("

%d\n

",ans[i]);return

0;}

思路2:可持久化線段樹

#include#define f(a)  for(int i=1;i<=a;i++)

const

int n=1000005

;using

namespace

std;

int a[n],n,q,rt[n*20

];int i()

struct

persistable_segment_tree

int mid=(l+r)>>1;build(lc[o],l,mid);build(rc[o],mid+1

,r);}

inline

void ins(int &o,int pre,int l,int r,int q,int

v)int mid=(l+r)>>1

; q

<=mid?ins(lc[o],lc[pre],l,mid,q,v):ins(rc[o],rc[pre],mid+1

,r,q,v);}

inline

int query(int o,int l,int r,int

q)}t;

int main()

else printf("

%d\n

",t.query(rt[pre],1,n,x)),rt[i]=rt[pre];}

}

思路3:主席樹

#includeusing

namespace

std;

#define max 1000100

#define f(c) for(int i=1;i<=c;i++)

int i()

introot[max],a[max],n,m;

struct nodet[max*20

];int sum=0,tot=1

;void build(int now,int l,int r)

t[now].ls=++tot;int mid=(l+r)>>1

; build(tot,l,mid);t[now].rs=++tot;build(tot,mid+1

,r);}

void addnode(int now,int new,int k,int w)

int mid=(t[now].l+t[now].r)>>1

;

if(k<=mid)t[new].ls=++tot,addnode(t[now].ls,tot,k,w);

else t[new].rs=++tot,addnode(t[now].rs,tot,k,w);}

void query(int now,int

k)

int mid=(t[now].l+t[now].r)>>1

; k

<=mid?query(t[now].ls,k):query(t[now].rs,k);}

int main()

else}return

0;}

可持久化陣列

日常不想放題目 luogu p3919 模板 可持久化陣列 題目中要求可以查詢歷史狀態,最暴力的想法是開 a m n 的二維陣列,每次修改暴力複製並修改,每次查詢暴力掃瞄,時間複雜度是 o m n 的,但這顯然是不行的.這個時候其實很容易想到線段樹,但線段樹維護的是當前狀態而無法維護歷史狀態,一種暴...

模板 可持久化陣列

戳我 為了方便起見,處理的陣列長度為5,起始的陣列元素為1 5,修改是將第乙個位置的陣列元素改為2。建樹規則很簡單,只要在葉子節點上寫上該點的值就可以了。我們發現,這兩棵線段樹中只有乙個葉子節點的值發生了改變,而運算元非常多,假如每次都memset一下,然後修改乙個值,空間上的巨大開銷幾乎無法想象,...

可持久化專題(二) 可持久化陣列的實現

前言 呃,首先宣告,看這篇部落格前,最好先去學一學主席樹,畢竟可持久化陣列的實現是完全基於主席樹的 那些亂七八糟的玄學演算法請走開 l in klink link 主席樹詳見部落格可持久化專題 一 主席樹 可持久化線段樹 順便吐槽一句,可持久化陣列這個名字聽起來真的很智障。簡介 可持久化陣列支援單點...