1. 程式人生 > 實用技巧 >演算法初探 - 可持久化資料結構

演算法初探 - 可持久化資料結構

更新記錄

【1】2020.10.18-16:34

  • 1.初步的寫了寫

目錄

  • 可持久化陣列
  • 可持久化線段樹(咕咕咕)
  • 可持久化平衡樹(咕咕咕)
  • 可持久化並查集(咕咕咕)

正文

可持久化這個東西啊,簡單的來說就是增加題目難度通過奇妙的方式新建結點來儲存之前的資訊,以達到回退的目的

可持久化陣列

陣列是我們經常接觸的東西

但是一可持久化就成藍題了

這其實相當於單點修改單點查詢的主席樹

我們會發現一次操作最多更新 \(\lg n\) 個節點

於是我們把這 \(\lg n\) 個節點存一下即可

那麼怎麼存呢?

對於update(change)在每層遞迴的時候新建結點就可以

對於query直接複製

最後把根節點存一下即可

【程式碼實現】

#include<iostream>
#define fx(l,n) inline l n
#define N 14000001
using namespace std;
int v[N],n,m,ver,op,loc,val,root[N],node=1;
struct PT{
	int l,r,v;
}t[N];
fx(void,build)(int p,int l,int r){
	if(l==r){
		t[p].v=v[l];
		return;
	}
	int mid=(l+r)>>1;
	t[p].l=++node;
	build(t[p].l,l,mid);
	t[p].r=++node;
	build(t[p].r,mid+1,r);
}
fx(int,newnd)(int p){
	t[++node]=t[p];
	return node;
}
fx(int,change)(int p,int l,int r,int pl,int v){
	p=newnd(p);
	if(l==r){
		t[p].v=v;
	} else{
		int mid=(l+r)>>1;
		if(pl<=mid) t[p].l=change(t[p].l,l,mid,pl,v);
		else t[p].r=change(t[p].r,mid+1,r,pl,v);
	}
	return p;
}
fx(int,query)(int p,int l,int r,int pl){
	if(l==r){
		return t[p].v;
	} else{
		int mid=(l+r)>>1;
		if(pl<=mid) return query(t[p].l,l,mid,pl);
		else return query(t[p].r,mid+1,r,pl);
	}
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>v[i];
	build(1,1,n);
	root[0]=1;
	for(int i=1;i<=m;i++){
		cin>>ver>>op>>loc;
		if(op==1){
			cin>>val;
			root[i]=change(root[ver],1,n,loc,val);
		} else{
			cout<<query(root[ver],1,n,loc)<<"\n";
			root[i]=root[ver];
		}
	}
}