【模板】可持久化数组(可持久化线段树/平衡树)

题目背景

UPDATE : 最后一个点时间空间已经放大

标题即题意

有了可持久化数组,便可以实现很多衍生的可持久化功能(例如:可持久化并查集)

题目描述

如题,你需要维护这样的一个长度为 N N N 的数组,支持如下几种操作

  1. 在某个历史版本上修改某一个位置上的值

  2. 访问某个历史版本上的某一位置的值

此外,每进行一次操作(对于操作2,即为生成一个完全一样的版本,不作任何改动),就会生成一个新的版本。版本编号即为当前操作的编号(从1开始编号,版本0表示初始状态数组)

输入输出格式

输入格式:

输入的第一行包含两个正整数 N,M N, M N,M, 分别表示数组的长度和操作的个数。

第二行包含N N N个整数,依次为初始状态下数组各位的值(依次为 ai a_i ai1≤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 vi 1 loci valuei,即为在版本vi v_i vi的基础上,将 aloci a_{{loc}_i} aloci 修改为 valuei {value}_i valuei

  2. 对于操作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;
}

 

posted @ 2019-02-12 09:42  NKDEWSM  阅读(213)  评论(0编辑  收藏  举报