可持久化数组
金牌导航 可持久化数据结构-3
题目大意
给出一个序列a,让你执行若干操作,操作分为两种:
1.继承第v次操作后把第x个数改成y
2.查询第v次操作的第x个数的值
输入样例
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
输出样例
59
87
41
87
88
46
数据范围
1⩽N,M⩽106,1⩽xi⩽N,0⩽vi<i,−109⩽ai,yi⩽1091\leqslant N,M\leqslant 10^6,1\leqslant x_i\leqslant N,0\leqslant v_i< i,-10^9\leqslant a_i,y_i\leqslant 10^91⩽N,M⩽106,1⩽xi⩽N,0⩽vi<i,−109⩽ai,yi⩽109
解题思路
如果直接暴力存数组,每次操作copy一遍会TLE/MLE
这里可以用搜索树的方法,就是把每个操作和所继承的操作连一条边,然后搜索即可,时间O(m)O(m)O(m)(这里不做详解)
对于这样一个序列,可以用主席树来维护
对于每次修改就和模板一样,然后查询就直接搜目标节点即可
时间O(mlogn)O(mlogn)O(mlogn),不如搜索树?
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define N 1000010
using namespace std;
int n, m, x, y, v, p, w, g, num, a[N], s[N << 5], ls[N << 5], rs[N << 5], root[N];
int build(int l, int r) {int x = ++w;if (l == r) {s[x] = a[l];return x;}int mid = (l + r) >> 1;ls[x] = build(l, mid);rs[x] = build(mid + 1, r);return x;
}
int change(int lst, int v, int y, int l, int r) {int x = ++w;if (l == r) {s[x] = y;return x;}int mid = (l + r) >> 1;if (v <= mid)ls[x] = change(ls[lst], v, y, l, mid), rs[x] = rs[lst];elsels[x] = ls[lst], rs[x] = change(rs[lst], v, y, mid + 1, r);return x;
}
int ask(int v, int x, int l, int r) {if (l == r) {return s[v];}int mid = (l + r) >> 1;if (x <= mid)return ask(ls[v], x, l, mid);elsereturn ask(rs[v], x, mid + 1, r);
}
int main() {scanf("%d%d", &n, &m);for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);root[0] = build(1, n);for (int i = 1; i <= m; ++i) {scanf("%d%d%d", &v, &p, &x);if (p & 1) {scanf("%d", &y);root[i] = change(root[v], x, y, 1, n);//修改} else {root[i] = root[v];//数组没变,直接copyprintf("%d\n", ask(root[v], x, 1, n));//查询}}return 0;
}