P3919 【模板】可持久化线段树 1(可持久化数组)

题目链接

P3919 【模板】可持久化线段树 1(可持久化数组)

题目描述

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

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

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

输入格式

输入的第一行包含两个正整数 \(N, M\) ,分别表示数组的长度和操作的个数。
第二行包含 \(N\) 个整数,依次为初始状态下数组各位的值(依次为 \(a_{i} , 1 \leq i \leq N\) )。
接下来 \(M\) 行每行包含3或 4 个整数,代表两种操作之一 ( \(i\) 为基于的历史版本号) :

  1. 对于操作1,格式为 \(v_{i} 1 \operatorname{loc}_{i}\) value \(_{i}\) ,即为在版本 \(v_{i}\) 的基础上,将 \(a_{l o c_{i}}\) 修改为 value \(_{i}\)
  2. 对于操作 2 ,格式为 \(v_{i} 2 l o c_{i}\) ,即访问版本 \(v_{i}\) 中的 \(a_{l o c_{i}}\) 的值,生成一样版本的对象应为 \(v i\)

输出格式

输出包含若干行,依次为每个操作2的结果。

输入输出样例

输入

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

说明/提示

数据规模:

对于 \(30 \%\) 的数据: \(1 \leq N, M \leq 10^{3}\)
对于 \(50 \%\) 的数据: \(1 \leq N, M \leq 10^{4}\)
对于 \(70 \%\) 的数据: \(1 \leq N, M \leq 10^{5}\)
对于100%的数据: \(1 \leq N, M \leq 10^{6}, 1 \leq l o c_{i} \leq N, 0 \leq v_{i}<i,-10^{9} \leq a_{i}\), \(value_{i} \leq 10^{9}\)

解题思路

可持久化线段树(数组)

与主席树类似,只不过这里维护的版本信息是每次询问的信息,可持久化线段树当左右节点相等时说明当前节点为答案节点,修改和询问操作都类似

  • 时间复杂度:\(O((n+m)logn)\)

代码

// Problem: P3919 【模板】可持久化线段树 1(可持久化数组)
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3919
// Memory Limit: 500 MB
// Time Limit: 1500 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=1e6+5;
int n,m,a[N],idx,root[N];
struct T
{
	int l,r;
	int val;
}tr[N*40];
int build(int l,int r)
{
	int p=++idx;
	if(l==r)
	{
		tr[p].val=a[l];
		return p;
	}
	int mid=l+r>>1;
	tr[p].l=build(l,mid);
	tr[p].r=build(mid+1,r);
	return p;
}
int update(int lst,int x,int y,int l,int r)
{
	int p=++idx;
	tr[p]=tr[lst];
	if(l==r)
	{
		tr[p].val=y;
		return p;
	}
	int mid=l+r>>1;
	if(x<=mid)tr[p].l=update(tr[lst].l,x,y,l,mid);
	else
		tr[p].r=update(tr[lst].r,x,y,mid+1,r);
	return p;
}
int ask(int u,int x,int l,int r)
{
	if(l==r)
		return tr[u].val;
	int mid=l+r>>1;
	if(x<=mid)return ask(tr[u].l,x,l,mid);
	return ask(tr[u].r,x,mid+1,r);
}
int main()
{
    help;
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    root[0]=build(1,n);
    for(int i=1;i<=m;i++)
    {
    	int v,op,x,y;
    	cin>>v>>op>>x;
    	if(op==1)
    	{
    		cin>>y;
    		root[i]=update(root[v],x,y,1,n);
    	}
    	else
    	{
    		cout<<ask(root[v],x,1,n)<<'\n';
    		root[i]=root[v];
    	}
    }
    return 0;
}
posted @ 2022-04-24 16:07  zyy2001  阅读(29)  评论(0编辑  收藏  举报