【洛谷 P3919】可持久化线段树 1(可持久化数组)
题目大意:
让你维护一个数组,维护两个操作:
1.在数组的某个历史版本上修改一个数,修改后生成一个新的版本。
2 查询数组某个历史版本上的某个位置上数的值,将该版本拷贝一份作为新的版本。
思路:
主席树的模板。
关于主席树
建主席树,询问,修改。
每次在树中找到该历史版本,直接修改。
询问时将该历史版本复制即可。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<vector>
#define r register
#define rep(i,x,y) for(r ll i=x;i<=y;++i)
#define per(i,x,y) for(r ll i=x;i>=y;--i)
using namespace std;
typedef long long ll;
const ll V=1e6+10;
ll tree[V<<5],a[V];
ll lc[V<<5],rc[V<<5],x,y,k,t;
ll n,m,top,cnt,f[V<<5],ans,opt;
void build(ll &now,ll x,ll y)
{
now=++cnt;
if(x==y)
{
tree[now]=a[x];
return;
}
ll mid=x+y>>1;
build(lc[now],x,mid);
build(rc[now],mid+1,y);
}
void add(ll &now,ll pre,ll x,ll y,ll val,ll p)
{
now=++cnt;
lc[now]=lc[pre],rc[now]=rc[pre];
tree[now]=tree[pre];
if(x==y)
{
tree[now]=val;
return ;
}
ll mid=x+y>>1;
if(p<=mid) add(lc[now],lc[pre],x,mid,val,p);
else add(rc[now],rc[pre],mid+1,y,val,p);
}
ll ask(ll now,ll x,ll y,ll k)
{
if(x==y) return tree[now];
ll mid=x+y>>1;
if(k<=mid) return ask(lc[now],x,mid,k);
else return ask(rc[now],mid+1,y,k);
}
int main()
{
scanf("%lld%lld",&n,&m);
rep(i,1,n)
scanf("%lld",&a[i]);
build(f[0],1,n);
rep(i,1,m)
{
scanf("%lld%lld%lld",&t,&opt,&x);
if(opt==1)
{
scanf("%lld",&k);
add(f[i],f[t],1,n,k,x);
}
else
{
printf("%lld\n",ask(f[t],1,n,x));
f[i]=f[t];
}
}
return 0;
}