吐槽:
今天是集訓的最後一天,也不知道該學什麼,就再複習一下可持久化的思想,又鞭屍了一遍可持久化數組。
可持久化思想:
對于每次修改的數組我們建立一個新版本,因為我們是動态開點式,對于可以利用的點進行利用,是以空間方面會節省很大。我們将上一版本的樹複制一遍,将沒有利用到的點省去重新開這個點所多出的空間,用圖表示也就是将新開的一條鍊連上上一個沒有用到的點,形成的一顆新樹
對于多版本
root[]
數組的了解
對于剛剛學習可持久化主席樹,或者可持久化數組,我們都會見到一個,像我一樣的菜雞一定很困惑為什麼這樣就能新開一個新的版本,因為
root[ ]
數組儲存的是每一個版本的根節點,我們通過根節點向左向右查詢就能找到某一版本的值,因為從根建立,從根查詢是一樣的原理,由于建立出來了,是以查詢根據同樣原理查詢即可
root[ ]
#include<bits/stdc++.h>
using namespace std;
//可持久化并查集
const int maxn =1e6+5;
int n,m,cnt;
struct node
{
int l,r,val;
} tr[maxn*40];
int a[maxn];
int root[maxn];
void build(int &now,int l,int r)//建第一個版本的數組
{
now=++cnt;
if(l==r)
{
tr[now].val=a[l];
return ;
}
int mid=(l+r)>>1;
build(tr[now].l,l,mid);
build(tr[now].r,mid+1,r);
}
void modify(int ver,int &now,int l,int r,int pos,int w)//修改版本
{
now=++cnt;
tr[now]=tr[ver];
if(l==r)
{
tr[now].val=w;
return ;
}
int mid=l+r>>1;
if(mid>=pos)
{
modify(tr[ver].l,tr[now].l,l,mid,pos,w);
}
else
{
modify(tr[ver].r,tr[now].r,mid+1,r,pos,w);
}
}
int query(int ver,int l,int r,int pos)
{
if(l==r)
{
return tr[ver].val;
}
int mid=l+r>>1;
if(mid>=pos)
{
return query(tr[ver].l,l,mid,pos);
}
else
{
return query(tr[ver].r,mid+1,r,pos);
}
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
build(root[0],1,n);
for(int i=1; i<=m; i++)
{
int ver,op,pos,w;
scanf("%d %d",&ver,&op);
if(op==1)
{
scanf("%d %d",&pos,&w);
modify(root[ver],root[i],1,n,pos,w);
}
if(op==2)
{
scanf("%d",&pos);
printf("%d\n",query(root[ver],1,n,pos));
root[i]=root[ver];
}
}
}