【模板】可持久化数组(可持久化线段树/平衡树)
题目背景
UPDATE : 最后一个点时间空间已经放大
标题即题意
有了可持久化数组,便可以实现很多衍生的可持久化功能(例如:可持久化并查集)
题目描述
如题,你需要维护这样的一个长度为 N N N 的数组,支持如下几种操作
-
在某个历史版本上修改某一个位置上的值
-
访问某个历史版本上的某一位置的值
此外,每进行一次操作(对于操作2,即为生成一个完全一样的版本,不作任何改动),就会生成一个新的版本。版本编号即为当前操作的编号(从1开始编号,版本0表示初始状态数组)
输入输出格式
输入格式:
输入的第一行包含两个正整数 N,M N, M N,M, 分别表示数组的长度和操作的个数。
第二行包含N N N个整数,依次为初始状态下数组各位的值(依次为 ai a_i ai,1≤i≤N 1 \leq i \leq N 1≤i≤N)。
接下来M M M行每行包含3或4个整数,代表两种操作之一(i i i为基于的历史版本号):
-
对于操作1,格式为vi 1 loci valuei v_i \ 1 \ {loc}_i \ {value}_i vi 1 loci valuei,即为在版本vi v_i vi的基础上,将 aloci a_{{loc}_i} aloci 修改为 valuei {value}_i valuei
-
对于操作2,格式为vi 2 loci v_i \ 2 \ {loc}_i vi 2 loci,即访问版本vi v_i vi中的 aloci a_{{loc}_i} aloci的值,生成一样版本的对象应为vi
输出格式:
输出包含若干行,依次为每个操作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
#include<iostream> #include<cstdio> #include<algorithm> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include<map> #include<set> #include<vector> #include<queue> #include<bitset> #include<ctime> #include<time.h> #include<deque> #include<stack> #include<functional> #include<sstream> //#include<cctype> //#pragma GCC optimize(2) using namespace std; #define maxn 2000005 #define inf 0x7fffffff //#define INF 1e18 #define rdint(x) scanf("%d",&x) #define rdllt(x) scanf("%lld",&x) #define rdult(x) scanf("%lu",&x) #define rdlf(x) scanf("%lf",&x) #define rdstr(x) scanf("%s",x) #define mclr(x,a) memset((x),a,sizeof(x)) typedef long long ll; typedef unsigned long long ull; typedef unsigned int U; #define ms(x) memset((x),0,sizeof(x)) const long long int mod = 1e9 + 7; #define Mod 1000000000 #define sq(x) (x)*(x) #define eps 1e-5 typedef pair<int, int> pii; #define pi acos(-1.0) //const int N = 1005; #define REP(i,n) for(int i=0;i<(n);i++) typedef pair<int, int> pii; inline int rd() { int x = 0; char c = getchar(); bool f = false; while (!isdigit(c)) { if (c == '-') f = true; c = getchar(); } while (isdigit(c)) { x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return f ? -x : x; } ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a%b); } int sqr(int x) { return x * x; } /*ll ans; ll exgcd(ll a, ll b, ll &x, ll &y) { if (!b) { x = 1; y = 0; return a; } ans = exgcd(b, a%b, x, y); ll t = x; x = y; y = t - a / b * y; return ans; } */ int n, m; int rt[maxn]; int a[1000004]; struct node { int val[maxn * 10], ls[maxn * 10], rs[maxn * 10]; int tot = 0; inline void build(int &o, int l, int r) { o = ++tot; if (l == r) { val[o] = a[l]; return; } int mid = (l + r) >> 1; build(ls[o], l, mid); build(rs[o], mid + 1, r); } inline void upd(int &o, int pre, int l, int r, int Val,int x) { o = ++tot; val[o] = val[pre]; ls[o] = ls[pre]; rs[o] = rs[pre]; if (l == r) { val[o] = Val; return; } int mid = (l + r) >> 1; if (x <= mid)upd(ls[o], ls[pre], l, mid, Val, x); else upd(rs[o], rs[pre], mid + 1, r, Val, x); } inline int query(int o, int l, int r, int x) { if (l == r)return val[o]; int mid = (l + r) >> 1; if (x <= mid)return query(ls[o], l, mid, x); else return query(rs[o], mid + 1, r, x); } }seg; int main() { // ios::sync_with_stdio(0); n = rd(); m = rd(); for (int i = 1; i <= n; i++)a[i] = rd(); seg.build(rt[0], 1, n); for (int i = 1; i <= m; i++) { int V = rd(), opt = rd(), loc = rd(); if (opt == 1) { int vu = rd(); seg.upd(rt[i], rt[V], 1, n, vu, loc); } else { int ans = seg.query(rt[V], 1, n, loc); printf("%d\n", ans); rt[i] = rt[V]; } } return 0; }
EPFL - Fighting