参考博客
可持久化数据结构:可以保留每一个历史版本,若所有版本都既可以访问又可以修改,成为完全可持久化(可以回滚到某个历史版本)
时间线:
可持久化线段树
可持久化下标线段树
题目:
模板 可持久化数组
你需要维护一个长度为N的数组,支持如下几种操作:
1.在某个历史版本上修改某一个位置上的值
2.访问某个历史版本的某一位置的值
做法:
用下标线段树维护一个数组,对于每个版本建一棵线段树->空间O(QN)
用可持久化的思想进行优化
当a[id]的值发生改变时,会影响从根[1,N]–>叶子[id,id]这条链上的所有点,其他点不会被影响,受影响的点只有logN个,所有我们没必要单独再建一个线段树,可以只建新版本的logN个点,其他点与老版本共用
如图,当a[1]发生修改时的情况
这样我们既保存了旧版本又存下新版本,根节点1(白色)对应旧版本,根节点1(红色)对应新版本,这样保存下所有历史版本,而且空间得到优化
空间O(logN)
时间O(logN)
增加边复杂度为常数
赋值节点的操作
赋值节点时直接用赋值运算符 =
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;
}
完整代码
改成我自己风格的可持久化
#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];}}
}