平衡树
\(Splay\)
\(Splay\),一种平衡树,较大儿子的期望比例大概为 \(0.6\) 左右,优于 \(FHQ\_Treap\) 的 \(0.7\),也就是说一般情况下跑的是比较快的,时间复杂度在平衡树中算比较优秀。
\(Splay\) 的核心思想是旋转维持树的平衡,每次操作后就将操作节点调整到树的根节点,同时调整树的形态,也就是在 \(Splay\) 函数中调整了树的结构。至于大多数操作可以认为是与 \(Binary\) \(Search\) \(Tree\) 相同,只有一些改变是基于 \(Splay\) 特定功能的。
\(Splay\) 维护时间复杂度是依靠 \(Splay\) 函数的,也就是旋转父节点与子节点。并且当距离目标点距离超过 \(2\) 时,都会采用双旋的方式,原因也正是单旋无法改变平衡树的结构,也就是说写一个单旋平衡树甚至 \(BST\) 更劣,无法保证时间复杂度的情况下常数还大。旋转的方法是这样的:
- 若距离目标点只有 \(1\) 的距离了,那么直接转过去。
- 距离大于 \(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;
}
}

浙公网安备 33010602011771号