[Luogu 3919]【模板】可持久化数组(可持久化线段树/平衡树)
Description
如题,你需要维护这样的一个长度为 N 的数组,支持如下几种操作
-
在某个历史版本上修改某一个位置上的值
- 访问某个历史版本上的某一位置的值
此外,每进行一次操作(对于操作2,即为生成一个完全一样的版本,不作任何改动),就会生成一个新的版本。版本编号即为当前操作的编号(从1开始编号,版本0表示初始状态数组)
Input
输入的第一行包含两个正整数 N, M, 分别表示数组的长度和操作的个数。
第二行包含N个整数,依次为初始状态下数组各位的值(依次为 a_i,1≤i≤N)。
接下来M行每行包含3或4个整数,代表两种操作之一(ii为基于的历史版本号):
-
对于操作1,格式为vi 1 loci valuei,即为在版本v_ivi的基础上,将 aloci 修改为 valuei
- 对于操作2,格式为vi 2 loci ,即访问版本 vi 中的 aloci 的值
Output
输出包含若干行,依次为每个操作2的结果。
Sample Input
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
Sample Output
59
87
41
87
88
46
HINT
数据规模:
对于30%的数据:1≤N,M≤103
对于50%的数据:1≤N,M≤104
对于70%的数据:1≤N,M≤105
对于100%的数据:1≤N,M≤106,1≤loci≤N,0≤vi<i,−109≤ai,valuei≤109
经测试,正常常数的可持久化数组可以通过,请各位放心
数据略微凶残,请注意常数不要过大
另,此题I/O量较大,如果实在TLE请注意I/O优化
样例说明:
一共11个版本,编号从0-10,依次为:
-
0 : 59 46 14 87 41
-
1 : 59 46 14 87 41
-
2 : 14 46 14 87 41
-
3 : 57 46 14 87 41
-
4 : 88 46 14 87 41
-
5 : 88 46 14 87 41
-
6 : 59 46 14 87 41
-
7 : 59 46 14 87 41
-
8 : 88 46 14 87 41
-
9 : 14 46 14 87 41
- 10 : 59 46 14 87 91
题解
$rt$,当模板存着...
1 //It is made by Awson on 2017.10.3 2 #include <set> 3 #include <map> 4 #include <cmath> 5 #include <ctime> 6 #include <queue> 7 #include <stack> 8 #include <vector> 9 #include <cstdio> 10 #include <string> 11 #include <cstring> 12 #include <cstdlib> 13 #include <iostream> 14 #include <algorithm> 15 #define LL long long 16 #define Max(a, b) ((a) > (b) ? (a) : (b)) 17 #define Min(a, b) ((a) < (b) ? (a) : (b)) 18 #define sqr(x) ((x)*(x)) 19 #define insert INSERT 20 using namespace std; 21 const int N = 1e6; 22 void read(int &x) { 23 char ch; bool flag = 0; 24 for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar()); 25 for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar()); 26 x *= 1-2*flag; 27 } 28 29 struct node { 30 int key; 31 node *child[2]; 32 }sgm[N*20+5], *pos = sgm; 33 node* root[N+5]; 34 int n, m, a[N+5]; 35 int opt, v, loc, val; 36 37 void build(node *o, int l, int r) { 38 if (l == r) { 39 o->key = a[l]; 40 return; 41 } 42 int mid = (l+r)>>1; 43 o->child[0] = ++pos; build(o->child[0], l, mid); 44 o->child[1] = ++pos; build(o->child[1], mid+1, r); 45 } 46 void insert(node* &o, int l, int r, int loc, int val) { 47 node* tmp = o; 48 o = ++pos; 49 if (l == r) { 50 o->key = val; 51 return; 52 }else { 53 o->child[0] = tmp->child[0]; 54 o->child[1] = tmp->child[1]; 55 } 56 int mid = (l+r)>>1; 57 if (loc <= mid) insert(o->child[0], l, mid, loc, val); 58 else insert(o->child[1], mid+1, r, loc, val); 59 } 60 int query(node *o, int l, int r, int loc) { 61 if (l == r) return o->key; 62 int mid = (l+r)>>1; 63 if (loc <= mid) return query(o->child[0], l, mid, loc); 64 else return query(o->child[1], mid+1, r, loc); 65 } 66 void work() { 67 read(n), read(m); 68 for (int i = 1; i <= n; i++) read(a[i]); 69 root[0] = pos; 70 build(root[0], 1, n); 71 for (int i = 1; i <= m; i++) { 72 read(v), read(opt); 73 if (opt == 1) { 74 read(loc), read(val); 75 root[i] = root[v]; 76 insert(root[i], 1, n, loc, val); 77 } 78 else { 79 read(loc); 80 root[i] = root[v]; 81 printf("%d\n", query(root[i], 1, n, loc)); 82 } 83 } 84 } 85 int main() { 86 work(); 87 return 0; 88 }