1. 程式人生 > >可持久化數組(可持久化線段樹/平衡樹)

可持久化數組(可持久化線段樹/平衡樹)

space print align left 版本號 此外 cnblogs include 輸出格式

題目背景

UPDATE : 最後一個點時間空間已經放大

標題即題意

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

題目描述

如題,你需要維護這樣的一個長度為 N N N 的數組,支持如下幾種操作

  1. 在某個歷史版本上修改某一個位置上的值

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

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

輸入輸出格式

輸入格式:

輸入的第一行包含兩個正整數 N,M N, M N,M, 分別表示數組的長度和操作的個數。

第二行包含N N N個整數,依次為初始狀態下數組各位的值(依次為 ai a_i a?i??,1≤i≤N 1 \leq i \leq N 1iN)。

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

  1. 對於操作1,格式為vi 1 loci valuei v_i \ 1 \ {loc}_i \ {value}_i v?i?? 1 loc?i?? value?i??,即為在版本vi v_i v?i??的基礎上,將 aloci a_{{loc}_i} a?loc?i???? 修改為 valuei {value}_i value?i??

  2. 對於操作2,格式為vi 2 loci v_i \ 2 \ {loc}_i v?i?? 2 loc?i??,即訪問版本vi v_i v?i??中的 aloci a_{{loc}_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

主席樹水題

用主席樹維護一下每次數組的版本就行

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using
namespace std; 6 const int N=1000000; 7 struct Node 8 { 9 int val; 10 Node *ch[2]; 11 }S[N*20],*pos=S; 12 Node *root[N+5]; 13 int a[N+5],b[N+5],n,m,sz,rem[N+5]; 14 void build(Node* &rt,int l,int r) 15 { 16 rt=++pos; 17 if (l==r) 18 {rt->val=a[l]; 19 return; 20 } 21 int mid=(l+r)/2; 22 build(rt->ch[0],l,mid); 23 build(rt->ch[1],mid+1,r); 24 } 25 void insert(Node* &rt,int l,int r,int k,int w) 26 { 27 Node *x=rt; 28 rt=++pos; 29 rt->ch[0]=x->ch[0]; 30 rt->ch[1]=x->ch[1]; 31 if (l==r) 32 {rt->val=w; 33 return; 34 } 35 int mid=(l+r)/2; 36 if (k<=mid) insert(rt->ch[0],l,mid,k,w); 37 else insert(rt->ch[1],mid+1,r,k,w); 38 } 39 int query(Node* rt,int l,int r,int k) 40 { 41 if (l==r) return rt->val; 42 int mid=(l+r)/2; 43 if (mid>=k) return query(rt->ch[0],l,mid,k); 44 else return query(rt->ch[1],mid+1,r,k); 45 } 46 int main() 47 {int i,j,x,y,k,p,v,w; 48 cin>>n>>m; 49 for (i=1;i<=n;i++) 50 { 51 scanf("%d",&a[i]); 52 b[i]=a[i]; 53 } 54 build(root[0],1,n); 55 for (i=1;i<=m;i++) 56 { 57 scanf("%d%d",&p,&v); 58 if (v==1) 59 { 60 scanf("%d%d",&k,&w); 61 root[i]=root[p]; 62 insert(root[i],1,n,k,w); 63 } 64 else 65 { 66 scanf("%d",&k); 67 root[i]=root[p]; 68 printf("%d\n",query(root[i],1,n,k)); 69 } 70 } 71 }

可持久化數組(可持久化線段樹/平衡樹)