可持久化(一)
參考博客
可持久化數(shù)據(jù)結(jié)構(gòu):可以保留每一個歷史版本,若所有版本都既可以訪問又可以修改,成為完全可持久化(可以回滾到某個歷史版本)
時(shí)間線:
可持久化線段樹
可持久化下標(biāo)線段樹
題目:
模板 可持久化數(shù)組
你需要維護(hù)一個長度為N的數(shù)組,支持如下幾種操作:
1.在某個歷史版本上修改某一個位置上的值
2.訪問某個歷史版本的某一位置的值
做法:
用下標(biāo)線段樹維護(hù)一個數(shù)組,對于每個版本建一棵線段樹->空間O(QN)
用可持久化的思想進(jìn)行優(yōu)化
當(dāng)a[id]的值發(fā)生改變時(shí),會影響從根[1,N]–>葉子[id,id]這條鏈上的所有點(diǎn),其他點(diǎn)不會被影響,受影響的點(diǎn)只有l(wèi)ogN個,所有我們沒必要單獨(dú)再建一個線段樹,可以只建新版本的logN個點(diǎn),其他點(diǎn)與老版本共用
如圖,當(dāng)a[1]發(fā)生修改時(shí)的情況
這樣我們既保存了舊版本又存下新版本,根節(jié)點(diǎn)1(白色)對應(yīng)舊版本,根節(jié)點(diǎn)1(紅色)對應(yīng)新版本,這樣保存下所有歷史版本,而且空間得到優(yōu)化
空間O(logN)
時(shí)間O(logN)
增加邊復(fù)雜度為常數(shù)
賦值節(jié)點(diǎn)的操作
賦值節(jié)點(diǎn)時(shí)直接用賦值運(yùn)算符 =
int clone(int rt){top++;tr[top]=tr[rt];return top; }int update(int rt,int l,int r,int pos,int val){rt=clone(rt);if(l==r){tr[rt].val=val;return rt;}int mid=(l+r)>>1;if(pos<=mid)tr[rt].l=update(tr[rt].l,l,mid,pos,val);else tr[rt].r=update(tr[rt].r,mid+1,r,pos,val);return rt; }完整代碼
改成我自己風(fēng)格的可持久化
#include<bits/stdc++.h> #define debug(a,b) printf("%s = %d\n",a,b); using namespace std; typedef long long ll; typedef pair<int, int> PII; //Fe~Jozky const ll INF_ll=1e18; const int INF_int=0x3f3f3f3f; inline ll read(){ll s=0,w=1ll;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1ll;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10ll+((ch-'0')*1ll),ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w; } void rd_txt(){#ifdef ONLINE_JUDGE#elsefreopen("in.txt","r",stdin);#endif } const int maxn=1e6+9; int a[maxn]; int top=0; struct tree{int l,r,val; }tr[maxn*30]; int clone(int rt){top++;tr[top]=tr[rt];return top; } int build(int rt,int l,int r){rt=++top;if(l==r){tr[rt].val=a[l];return rt;}int mid=(l+r)>>1;tr[rt].l=build(tr[rt].l,l,mid);tr[rt].r=build(tr[rt].r,mid+1,r);return rt; } int update(int rt,int l,int r,int pos,int val){rt=clone(rt);if(l==r){tr[rt].val=val;return rt;}int mid=(l+r)>>1;if(pos<=mid)tr[rt].l=update(tr[rt].l,l,mid,pos,val);else tr[rt].r=update(tr[rt].r,mid+1,r,pos,val);return rt; } int query(int rt,int l,int r,int x){if(l==r)return tr[rt].val;int mid=l+r>>1;if(x<=mid)return query(tr[rt].l,l,mid,x);else return query(tr[rt].r,mid+1,r,x); } int Root[maxn]; int main() {rd_txt();int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",&a[i]);}Root[0]=build(0,1,n);for(int i=1;i<=m;i++){int rt,mode,x;scanf("%d%d%d",&rt,&mode,&x);if(mode==1){int y;scanf("%d",&y);Root[i]=update(Root[rt],1,n,x,y);}else {printf("%d\n",query(Root[rt],1,n,x));Root[i]=Root[rt];}} }總結(jié)
- 上一篇: 无线路由器中开启无线广播是什么意思路由器
- 下一篇: L2-005 集合相似度 (25分)