Splay基本操作

Instructions

Splay基本操作

using namespace std;
struct Splay{
	int data;
	int ch[2];
	int num;
	int FA;
	int size;
}t[maxn];
int newp;
void Rotate(int x){
	int y=t[x].FA,z=t[y].FA,k=(t[y].ch[1]==x);//y是x的父亲,z是y的父亲(x的祖父),k是x是y的哪个儿子 
	t[z].ch[y==t[z].ch[1]]=x;//把x变到y原来的位置 
	t[x].FA=z;//把x的父亲变成z 
	t[y].ch[k]=t[x].ch[k^1];//把y原来是x的位置的变成x相对于y的位置
	t[y].size=t[t[y].ch[k]].size+t[t[y].ch[k^1]].size;//把y的size更新 
	t[t[x].ch[k^1]].FA=y;//修改那个的父亲
	t[x].ch[k^1]=y;//把x的相应儿子改成y
	t[x].size==t[y].size+t[t[x].ch[k]].size;//更新x的size 
	t[y].FA=x;//把y的父亲改成x 
}
void splay_S(int x,int destnation){
	while(t[x].FA!=destnation){//如果没有把x旋成destnation的儿子 
		int y=t[x].FA,z=t[y].FA;//y父亲,z祖父 
		if(z!=destnation){//如果祖父还不是destnation 
			(t[z].ch[0]==y)^(t[y].ch[0]==x)?Rotate(x):Rotate(y);//如果共线旋y不共线旋x 
		}
		Rotate(x);//无论共不共线都要旋x 
	}
	if(destnation==0)root=x;//如果根节点是0那更新根节点 
}
void find(x){//找到x的位置并且把x旋上去 
	int u=root;
	if(!u)return;//如果是空树直接return 
	while(t[u].ch[x>t[u].data]&&x!=t[u].data){//如果还没有找到x的位置 
		u=t[u].ch[x>t[u].data];//如果x大于data就进右儿子否则进左儿子 
	}
	splay_S(x,0);//把x旋上去 
}
int Next_n(int x,bool flag){//寻找前驱||后继(flag==0是前驱,flag==1是后继) 
	find(x);//找到x的位置 
	int u=root;
	if(t[u].data<x&&!flag)return u;//如果根节点比x小且是找前驱直接return u 
	if(t[u].data>x&&flag)return u;//如果根节点比x大且是找后继直接return u
	u=t[u].ch[flag];//找前驱就找左儿子,后继就右儿子 
	while(t[u].ch[flag^1]){//当还没有遇到叶子结点的时候 
		u=t[u].ch[flag^1];//找前驱进入左儿子之后就找最右边的,找后继就进入右儿子之后找最左边的 
	}
	return u;//返回前驱或者后继的位置 
}
void insert(int x){
	int u=root,fa=0;
	while(u&&t[u].data!=x){//当还没有找到x或者还没有找到叶子结点的时候 
		fa=u;
		u=t[u].ch[x>t[u].data];
	}
	if(u){//如果x已经存在 
		t[u].num++;//更新该结点的num 
	}
	else{//否则 
		u=++newp;//重新建立一个结点 
		if(fa){//如果已经有父亲 
			t[fa].ch[x>t[fa].data]=u;//存成儿子 
		}
		t[u].ch[0]=t[u].ch[1]=0;//新加的点是叶子结点没有儿子 
		t[u].FA=fa;//把父亲更新 
		t[u].data=x;//更新data 
		t[u].num=1;//更新num 
		t[u].size=1;//更新size 
	}
	splay_S(u,0);//把该结点旋上去 
}
void Delete_d(int x){//删除一个点 
	int Pre_x=Next_n(x,0);//找前驱 
	int Suc_x=Next_n(x,1);//找后继 
	splay_S(Pre_x,0);//把前驱旋到根节点 
	splay_S(Suc_x,Pre_x);//把后继旋到前驱 
	int del=t[Suc_x].ch[0];
	if(t[del].cnt>1){//如果有多个该结点 
		t[del].cnt--;//删去一个 
		splay_S(del,0);//旋上去 
	}
	else t[Suc_x].ch[0]=0;//否则直接删去这个点 
}
原文地址:https://www.cnblogs.com/virtual-north-Illya/p/10045273.html