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 \ _ivi1locivaluei,即為在版本v_ivi的基礎上,將 a__i}aloci修改為 _ivaluei
對於操作2,格式為v_i \ 2 \ _ivi2loci,即訪問版本v_ivi中的 a__i}aloci的值
輸出格式:
輸出包含若干行,依次為每個操作2的結果。
輸入樣例#1:
5 1059 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:
598741
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:主席樹
#includeusingnamespace
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 主席樹詳見部落格可持久化專題 一 主席樹 可持久化線段樹 順便吐槽一句,可持久化陣列這個名字聽起來真的很智障。簡介 可持久化陣列支援單點...