DS笔记

数据结构都快忘了,再学点。

分块学习笔记

以上的不会再写,只会再写别的。

DS都快忘了。

分块学习笔记不会再写,只会再写别的。

平衡树

众所周知,BST很方便,就是会退化成链或树很高,所以我们需要更高效的DS,那就是——平衡树。

Splay

Splay好闪,拜谢Splay。

Splay是通过不断将某个节点旋转至根来保持平衡,同时满足BST的性质。

怎么旋转呢?我们来画两张图!

左旋

这是一张图:

经过左旋后变为:

可以看出就是将 \(2\) 的右儿子 \(1\) 变为 \(2\) 的父亲,然后把 \(1\) 的左儿子变成了 \(2\) 的右儿子(也就是变为 \(1\) 的孙子)。

右旋

和左旋相反,下边给出图示(其实就是图片倒了一下):

经过右旋后变为:

同样可以看出,就是将 \(1\) 的左儿子 \(2\) 变为 \(1\) 的父亲,然后把 \(2\) 的右儿子变成了 \(1\) 的左儿子(也就是变为 \(2\) 的孙子)。

其实就是相反的

某个节点的旋转就是这样的:

  • 如果他是某个节点的左儿子,就右旋。

  • 如果他是某个节点的右儿子,就左旋。


但是旋一次只会和父亲交换而不是到根,咋整?

答案是暴力。

是的,你没看错,只需要暴力转就可以了。

那不就写完了?溜了溜了

别急!这是单旋Splay,它在棺材里躺得好好的呢!

单旋Splay很容易被卡到链。

如下图,如果有三点共线的情况,那么最后跳来跳去还是一条链,那咋办?

先转 \(2\) 再转 \(3\) 即可。

然后我们也可以得出规律了,就是先转父亲,再转自己一直这样直到自己变成根。

下面借一下大佬Enoch006的图,就是这样修改的:

接下来讲代码和操作啦。

先来声明一下变量捏。

siz//代表整棵Splay的大小
root//Splay的根节点
sz[i]//i的子树的大小
num[i]//i这个节点的值
cnt[i]//i这个节点的值出现的次数
fa[i]//i的父亲
son[i][0]//i的左儿子
son[i][1]//i的右儿子

清空

这个操作在删除后执行。

void all_zero(int x){
	fa[x]=0;
	son[x][0]=0;
	son[x][1]=0;
	num[x]=0;
	cnt[x]=0;
	sz[x]=0;
}

get

判断当前的点是左儿子还是右儿子(旋转要用)。

int get(int x){
	if(x==son[fa[x]][0]){
		return 0;
	}return 1;
}

pushup

随便写的名字

用于修改后确认并修改树的大小。

void pushup(int x){
	if(x>=1){
		sz[x]=cnt[x];
		if(son[x][0]>=1){
			sz[x]+=sz[son[x][0]];
		}if(son[x][1]>=1){
			sz[x]+=sz[son[x][1]];
		}
	}
}

rotate

如下图。

我们要旋转 \(4\),就会变成下面的:

一开始 \(4\) 的父亲是 \(2\)\(2\) 的父亲是 \(1\)

flagget(4),那么就是 \(4\) 是左儿子还是右儿子。

那么可以发现,\(2\)flag 儿子和 \(4\)flag^1 儿子还有 \(1\) 的或左或右的儿子(就是看一开始 \(2\) 是哪个儿子)都要换。

其实旋转就是连边、断边。

(下面的数字就是上面那棵树的节点)。

于是我们先把 \(2\)\(6\) 连上,再连 \(4\)\(2\),最后连 \(1\)\(2\)

那么旋转就好了。

void rotate(int x){
	int f=fa[x],flag=get(x);
	int gra=fa[f];
	son[f][flag]=son[x][flag^1];
	fa[son[f][flag]]=f;
	son[x][flag^1]=f;
	fa[f]=x,fa[x]=gra;
	if(gra>=1){
		if(son[gra][1]==f){
			son[gra][1]=x
		}else{
			son[gra][0]=x
		}
	}pushup(f),pushup(x);
}

Splay

双旋的关键。

这里判断两种情况:

  • 三点一线,这样就是上面说的,先转父亲,再转自己一直这样直到自己变成根。

  • 不是三点一线,疯狂暴力旋转即可。

void Splay(int x){
	for(int f=0,f=fa[x];rotate(x)){
		if(fa[f]>=1){
			if(get(x)==get(fa)){
				rotate(fa);
			}else{
				rotate(x);
			}
		}
	}rt=x;
}

insert

也是分类讨论:

  • 如果 rt==0,那么树肯定是空的,那么

咕了。

posted @ 2024-03-01 21:47  scy_qwq  阅读(5)  评论(0编辑  收藏  举报