题解 P3919 【【模板】可持久化数组(可持久化线段树/平衡树)】
可持久化数组,可以访问历史版本的数组。
我们考虑使用可持久化数据结构——主席树,如果不理解可以左转模板。
主席树对数组的每一个前缀建树。我们都知道其中
什么意思呢?看图(我们设这个数组为a={1,2,3,4}):
我们发现,这棵线段树叶子节点的权值就是它所对应数组内数的权值,这和普通线段树是类似的。
但是我们令非叶子节点的权值为空。这只是为了方便二分查找而设置的。
所以我们在查询数组内数的值时,直接单点询问就可以了,时间复杂度
int query(int rt,int l,int r,int kkk){
if (l==r) return tree[rt].sum;
int mid=(l+r)>>1;
if (kkk<=mid) return query(tree[rt].l,l,mid,kkk);
else return query(tree[rt].r,mid+1,r,kkk);
}
主程序内:
query(树根,1,n,访问数组的下标);
我们令初始状态为第
和主席树一样,数组
创造右节点。
然后
随后,创造新的叶子节点(
代码和主席树神似。
void build(int &rt,int l,int r){
rt=++cnt;
if(l==r){tree[rt].sum=a[l];return;}
int mid=(l+r)>>1;
build(tree[rt].l,l,mid);build(tree[rt].r,mid+1,r);
}//初始建设
void update(int num,int &rt,int l,int r){
tree[++cnt]=tree[rt]; rt=cnt;
int mid=(l+r)/2;
if (l==r){tree[rt].sum=aaaa; return;}
if (num<=mid) update(num,tree[rt].l,l,mid);
else update(num,tree[rt].r,mid+1,r);
}//更新
时间复杂度
这么一来,回到某一个状态,就很简单了,若要访问某一个状态i,访问或更新时直接使用
代码如下:
#include<bits/stdc++.h>
#define res register int
#define ll long long
#define jsz inline
using namespace std;
int cnt,n,a[1000660],m,root[1000660],aaaa;
jsz int read(){
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){
if (ch=='-')f=-1;
ch=getchar();
}
while (isdigit(ch)){
x=x*10+ch-48;
ch=getchar();
}
return x*f;
}
struct ZXT{
int l,r,sum;
}tree[20006660];
jsz void build(int &rt,int l,int r){
rt=++cnt;
if(l==r){tree[rt].sum=a[l];return;}
int mid=(l+r)>>1;
build(tree[rt].l,l,mid);build(tree[rt].r,mid+1,r);
}
jsz void update(int num,int &rt,int l,int r){
tree[++cnt]=tree[rt]; rt=cnt;
int mid=(l+r)/2;
if (l==r){tree[rt].sum=aaaa; return;}
if (num<=mid) update(num,tree[rt].l,l,mid);
else update(num,tree[rt].r,mid+1,r);
}
jsz int query(int rt,int l,int r,int kkk){
if (l==r) return tree[rt].sum;
int mid=(l+r)>>1;
if (kkk<=mid) return query(tree[rt].l,l,mid,kkk);
else return query(tree[rt].r,mid+1,r,kkk);
}
int main(){
n=read();m=read();
for (res i=1;i<=n;i++) a[i]=read();
build(root[0],1,n);
for (res i=1;i<=m;i++){
int xxxx=read();int yyyy=read();
if (yyyy==1){
int zzzz=read();aaaa=read();
root[i]=root[xxxx];
update(zzzz,root[i],1,n);
}else{
int zzzz=read();
printf("%d\n",query(root[xxxx],1,n,zzzz));
root[i]=root[xxxx];
}
}
}