可持久化线段树
可持久化线段树
维护一个长度为
的数组,支持如下几种操作
在某个历史版本上修改某一个位置上的值
访问某个历史版本上的某一位置的值
此外,每进行一次操作(对于操作2,即为生成一个完全一样的版本,不作任何改动),就会生成一个新的版本。版本编号即为当前操作的编号(从1开始编号,版本0表示初始状态数组)
(
显然不能开
由线段树得到启发,每次修改时只会经过约 tree[MAXN<<5]
一般也不会爆。
每次查询时只需要沿对应版本的根节点向下查找即可。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
struct Stree{
int ls,rs;//左儿子 右儿子
int num;
#define ls(x) tree[x].ls
#define rs(x) tree[x].rs
#define num(x) tree[x].num
}tree[N<<5];
int n,m,a[N],root[N<<5],cnt;
int rt,op,x,y;
int build(int l,int r){//l r 为当前节点区间
int x=++cnt;
if(l==r){
num(x)=a[l];
return x;
}
int mid=l+r>>1;
ls(x)=build(l,mid);
rs(x)=build(mid+1,r);
return x;
}
int change(int x,int l,int r,int i,int num){//x 为原版当前节点 l r 为当前节点区间
int y=++cnt;//y 为新版当前节点
if(l==r){
num(y)=num;
return y;
}
int mid=l+r>>1;
ls(y)=ls(x);
rs(y)=rs(x);
if(i<=mid)//更改左儿子则新建左儿子,更改右儿子则新建右儿子
ls(y)=change(ls(x),l,mid,i,num);
else
rs(y)=change(rs(x),mid+1,r,i,num);
return y;
}
int query(int x,int l,int r,int i){
if(l==r)
return num(x);
int mid=l+r>>1;
if(i<=mid)
return query(ls(x),l,mid,i);
else
return query(rs(x),mid+1,r,i);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
root[0]=build(1,n);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&rt,&op,&x);
if(op==1){
scanf("%d",&y);
root[i]=change(root[rt],1,n,x,y);
}else{
printf("%d\n",query(root[rt],1,n,x));
root[i]=root[rt];
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具