平衡树

\(Splay\)

\(Splay\),一种平衡树,较大儿子的期望比例大概为 \(0.6\) 左右,优于 \(FHQ\_Treap\)\(0.7\),也就是说一般情况下跑的是比较快的,时间复杂度在平衡树中算比较优秀。

\(Splay\) 的核心思想是旋转维持树的平衡,每次操作后就将操作节点调整到树的根节点,同时调整树的形态,也就是在 \(Splay\) 函数中调整了树的结构。至于大多数操作可以认为是与 \(Binary\) \(Search\) \(Tree\) 相同,只有一些改变是基于 \(Splay\) 特定功能的。

\(Splay\) 维护时间复杂度是依靠 \(Splay\) 函数的,也就是旋转父节点与子节点。并且当距离目标点距离超过 \(2\) 时,都会采用双旋的方式,原因也正是单旋无法改变平衡树的结构,也就是说写一个单旋平衡树甚至 \(BST\) 更劣,无法保证时间复杂度的情况下常数还大。旋转的方法是这样的:

  1. 若距离目标点只有 \(1\) 的距离了,那么直接转过去。
  2. 距离大于 \(2\),看两个该节点与其父节点相对于他们各自的父亲在不在同一边,如果在则先转父亲再转儿子,否则就直接转两次儿子,可以理论使一条长度为 \(n\) 的链变为 \(\frac{n}{2}\)

笛卡尔树

性质

笛卡尔树是二叉查找树的一种,每个节点都是一个键值二元组 \((key,value)\),其中 \(key\) 满足二叉查找树的性质(左儿子小于父亲,右儿子大于父亲),而 \(value\) 则满足堆的性质(左儿子与右儿子总大于或小于父亲)。因此,当 \(key\)\(value\) 两两不同时,笛卡尔树是唯一确定的。

\(Treap\) 本质上也是笛卡尔树的一种,只不过其键值是随机的来保证其平衡性。

函数

\(Build\)

构建笛卡尔树时,首先

inline void build(){
	for(register int i = 1; i <= n; ++i){
		int now = top;
		while(k > 0 && a[stk[now]] > a[i])	k--;
		if(now)	son[stk[now]][1] = i;
		if(now < top)	son[i][0] = stk[now + 1];
		stk[++now] = i;
		top = now;
	}
}

\(FHQ\)_\(Treap\)

posted @ 2024-10-09 18:25  Zzzzzzzm  阅读(16)  评论(0)    收藏  举报