Splay的一些操作
Posted idqi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Splay的一些操作相关的知识,希望对你有一定的参考价值。
Splay : 十分happy的数据结构(过于灵活)
推荐:https://blog.csdn.net/Clove_unique/article/details/50630280
简单的定义:
fa[x]为x的父亲,son[x][0/1]为x的左右儿子
简单的操作
get(x):查找x为父亲的哪一个儿子
int get(int x) {return son[fa[x]][1]==x;}
rotate(x):将x旋转到父亲
void rotate(int x) { int y=fa[x],z=fa[y],k=get(x); if (z) son[z][get(y)]=x;fa[x]=z; son[y][k]=son[x][k^1]; if(son[y][k]) fa[son[y][k]]=y; son[x][k^1]=y;fa[y]=x;update(y);update(x); }
Splay(x,goal):将x旋转到goal的儿子
void Splay(int x,int goal,int k) { while(fa[x]!=goal) { int y=fa[x],z=fa[y]; if(z!=goal) rotate(get(y)==get(x)?y:x); rotate(x); } if(goal==0) rt[k]=x; }
Splay的任何旋转操作不影响这个树的中序遍历
因此可以维护一个数组:
对于每一个节点为 size 表示整个子树的和
数组的下标 -> 树上排名 -> 中序遍历的位置
那么直接可以通过互换一个节点左右儿子,改变名次
Splay之间的互相插入
遍历一遍 + 插入
清空x
void earse(int x) {fa[x]=son[x][0]=son[x][1]=num[x]=tol[x]=0;}
插入x到rt[k]的Splay
void inst(int y,int k) { int x=rt[k],f=0; while(x) { if(vi[x]==vi[y]) { num[x]=max(num[x],num[y]); tol[x]=max(tol[x],num[x]); earse(y);return ; } f=x;x=son[x][vi[y]>vi[x]]; } fa[y]=f;son[f][vi[y]>vi[f]]=y; tol[y]=num[y];update(f);Splay(y,0,k); }
遍历
void merge(int x,int a) // x -> a { if(!x) return ; merge(son[x][0],a);merge(son[x][1],a); son[x][0]=son[x][1]=0;inst(x,a); }
汇总:
int rt[N]; struct tree { int son[N][2],vi[N],fa[N],num[N],tol[N],tot; void clear() { memset(fa,0,sizeof(fa)); memset(vi,0,sizeof(vi)); memset(son,0,sizeof(son)); memset(num,0,sizeof(num)); memset(tol,0,sizeof(tol)); } int get(int x) {return son[fa[x]][1]==x;} void update(int x){if(x) tol[x]=max(num[x],max(tol[son[x][0]],tol[son[x][1]]));} void rotate(int x) { int y=fa[x],z=fa[y],k=get(x); if (z) son[z][get(y)]=x;fa[x]=z; son[y][k]=son[x][k^1]; if(son[y][k]) fa[son[y][k]]=y; son[x][k^1]=y;fa[y]=x;update(y);update(x); } void Splay(int x,int goal,int k) { while(fa[x]!=goal) { int y=fa[x],z=fa[y]; if(z!=goal) rotate(get(y)==get(x)?y:x); rotate(x); } if(goal==0) rt[k]=x; } void ins(int d,int fs,int k) { int x=rt[k],f=0; if(!x) {++tot;vi[tot]=d;num[tot]=tol[tot]=fs;Splay(tot,0,k);return ;} while(x) { if(vi[x]==d) {num[x]=max(num[x],fs);tol[x]=max(tol[x],fs);return ;} f=x;x=son[x][d>vi[x]]; } ++tot;fa[tot]=f;son[f][d>vi[f]]=tot;vi[tot]=d; num[tot]=tol[tot]=fs;update(f);Splay(tot,0,k); } void earse(int x) {fa[x]=son[x][0]=son[x][1]=num[x]=tol[x]=0;} void inst(int y,int k) { int x=rt[k],f=0; while(x) { if(vi[x]==vi[y]) { num[x]=max(num[x],num[y]); tol[x]=max(tol[x],num[x]); earse(y);return ; } f=x;x=son[x][vi[y]>vi[x]]; } fa[y]=f;son[f][vi[y]>vi[f]]=y; tol[y]=num[y];update(f);Splay(y,0,k); } int find(int d,int k) { int x=rt[k],up=0; while(x) { if(vi[x]<d) up=x; x=son[x][d>vi[x]]; } return up; } void merge(int x,int a) // x -> a { if(!x) return ; merge(son[x][0],a);merge(son[x][1],a); son[x][0]=son[x][1]=0;inst(x,a); } } T;
以上是关于Splay的一些操作的主要内容,如果未能解决你的问题,请参考以下文章