【模板】可持久化平衡树
借这一篇随笔说一下我对可持久化数据结构的一些思考。
先说题目本身。平衡树可持久化一般用无旋Treap来实现,因为它没有旋转,也就是说假如你指向了某个子树,那么子树内的东西就不会改变,而这一点Splay或者Treap就不太好搞(替罪羊暂时不会写【汗颜】)。于是按照主席树一样的思路,在操作的过程中每次都新建一个节点使之和旧节点完全一样,接下来考虑两个节点可能相异的地方有哪些。对于split操作来说,一个点属于左半树为例,新节点和旧节点显然左子树所有信息相同,不同的只有右子树的链接,递归处理即可。merge则更加简单,新建一个节点全等于优先级小的点之后考虑有什么变化,显然可以想到新旧节点只会有一个孩子有变化,那么递归处理即可。空间开销比较大,所幸本题空间给的也大(1000MB),便没有什么问题了。
至于可持久化数据结构,几道模板的描述都是什么基于某个历史版本的操作。其实我觉得全部描述成一棵树比较合适,因为相当于每个历史状态单前驱多后继,可以解决的问题就多了起来。
code
#include<cstdio>
#include<cstdlib>
#include<ctime>
#define zczc
using namespace std;
const int N=500010;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w>='0'&&w<='9'){wh=wh*10+w-'0';w=getchar();}
wh*=f;return;
}
#define lc t[x].l
#define rc t[x].r
struct node{
int l,r,data,size,p;
}t[N<<6];
int ti,root[N],cnt;
inline void print(int x){
if(!x)return;
printf("%d %d %d&%d\n",x,t[x].data,lc,rc);
print(lc);print(rc);
}
inline void pushup(int x){
t[x].size=t[lc].size+t[rc].size+1;
}
inline int newone(int val){
t[++cnt]=(node){0,0,val,1,rand()};return cnt;
}
inline void split(int x,int val,int &a,int &b){
if(!x){a=b=0;return;}
int y=x;x=++cnt;t[x]=t[y];
if(t[x].data<=val){a=x;split(rc,val,rc,b);}
else{b=x;split(lc,val,a,lc);}pushup(x);
}
inline int merge(int x,int y){
if(!x||!y)return x+y;int s=++cnt;
if(t[x].p<t[y].p){t[s]=t[x];t[s].r=merge(t[s].r,y);}
else{t[s]=t[y];t[s].l=merge(x,t[s].l);}pushup(s);return s;
}
inline void insert(int pl,int val){
int a,b;split(root[pl],val,a,b);
root[ti]=merge(merge(a,newone(val)),b);
}
inline void delet(int pl,int val){
int a,b,c;split(root[pl],val,a,c);
split(a,val-1,a,b);b=merge(t[b].l,t[b].r);
root[ti]=merge(merge(a,b),c);
}
inline int get(int x,int val){
if(t[lc].size+1==val)return t[x].data;
if(t[lc].size>=val)return get(lc,val);
else return get(rc,val-t[lc].size-1);
}
inline int getmax(int pl,int val){
int a,b;split(root[pl],val-1,a,b);
return get(a,t[a].size);
}
inline int getmin(int pl,int val){
int a,b;split(root[pl],val,a,b);
return get(b,1);
}
inline int getrank(int pl,int val){
int a,b;split(root[pl],val-1,a,b);
return t[a].size+1;
}
#undef lc
#undef rc
signed main(){
#ifdef zczc
freopen("in.txt","r",stdin);
#endif
srand(time(0));
int m,op,h,val;
read(m);
for(ti=1;ti<=m;ti++){
read(h);read(op);read(val);
switch(op){
case 1:insert(h,val);break;
case 2:delet(h,val);break;
case 3:printf("%d\n",getrank(h,val));break;
case 4:printf("%d\n",get(root[h],val));break;
case 5:printf("%d\n",getmax(h,val));break;
case 6:printf("%d\n",getmin(h,val));break;
}
if(op>2)root[ti]=root[h];
//print(root[ti]);printf("\n");
}
return 0;
}
一如既往,万事胜意
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)