关于平衡树的一些总结

平衡树是个大专题啊qwq。。最近也学了一些很有用的平衡树,写个总结吧。。

一.splay

学的第一个平衡树,复习一下。。

splay是一个功能很强大的二叉搜索树。其实讲道理splay并不算平衡树吧,因为它并没有任何关于树高的限制。splay的原理就是,每次插入或查询一个结点,就把它旋转到根结点,这样与搜索引擎的原理类似,查询次数较多的结点就能更靠近根。splay并不能保证每次操作严格复杂度都是O(logn),但是每次操作的均摊复杂度确实可以是O(log)。。然而我也不知道为什么。。不过splay好像有可能会被卡来着。。但是splay在序列上的操作可以说几乎完美,因为它可以任意旋转。splay的编程复杂度也是很小的。

splay的核心在于splay操作,即调用splay(x,f),就是把x旋转到f的儿子上(特别地,如果把x旋到根那么f=0)。splay的旋转分为3种——zig,zig-zig,zig-zag。zig操作,就是当x的父亲已经是f的儿子时,直接旋转x。zig-zig,当x与x的父亲位于同一侧时(就是说,x是x的父亲的左儿子,x的父亲是x的父亲的父亲的左儿子,反之也成立)。先旋转x的父亲,再旋转x。zig-zag,当x与x的父亲位于不同侧时,直接旋转两次x。这里的旋转,就是指,如果x是它父亲的左儿子,那么就把他右旋,否则左旋。感觉上个图会更容易理解些。。

然后就是上代码了。。

 1 il void rotate(RG int x){
 2     RG int y=fa[x],z=fa[y],k=ch[y][0]==x;
 3     ch[z][ch[z][1]==y]=x,fa[x]=z;
 4     ch[y][k^1]=ch[x][k],fa[ch[x][k]]=y;
 5     ch[x][k]=y,fa[y]=x,pushup(y),pushup(x); return;
 6 }
 7
 8 il void splay(RG int x,RG int goal){
 9     RG int top=0; st[++top]=x;
10     for (RG int i=x;fa[i]!=goal;i=fa[i]) st[++top]=fa[i];
11     for (RG int i=top;i;--i) if (lazy[st[i]]) pushdown(st[i]);
12     while (fa[x]!=goal){
13     RG int y=fa[x],z=fa[y];
14     if (fa[y]!=goal){
15         ((ch[z][0]==y)^(ch[y][0]==x)) ? rotate(x) : rotate(y);
16     }
17     rotate(x);
18     }
19     if (!goal) rt=x; return;
20 }

splay还是很好写的吧,还能对一个序列进行分裂和合并这种神奇的操作qwq。。

二.替罪羊树

替罪羊树也是一种很好写的平衡树qwq。。替罪羊树的核心思想就是重构。即当一棵子树的平衡被破坏,那么就把这棵树拍平,也就是树高为O(logn)的完美二叉树形态。这样看似复杂度很高,实则不然。可以证明,替罪羊树每次重构的复杂度都是均摊O(logn)的。反正我也不会证明,证明还要用物理学知识。。

---------------------------------------------------------------------------------------------------------------------------------------------------

具体是这样操作的:我们设定一个参数α,满足α∈[0.5,1)。(其实如果你设定α为0.5那就会T飞~)

α高度平衡:树高h≤log1an

α大小平衡:对于一个结点p满足max(sizelp,sizerp)≤αsizep

如果每个结点均满足α大小平衡,假设最深的点为dd,那么有1≤nαdepd

那么depd≤logα1n=log1αndepd≤logα1n=log1αn,即满足α高度平衡。

插入和普通BST类似,只需要判断插入操作是否导致了这一条链上结点的大小平衡被破坏,如果有的话将深度最浅的点所在子树暴力重建。重建最简单的方法就是对这棵子树中序遍历后分治建树。通过势能分析可以证明每一次插入的均摊复杂度为logn。

查询和普通BST并无区别。

删除操作比较巧妙。对于一次删除,我们并不马上移除这个点,而是直接这个点上打上删除标记,查询时跳过该点。重构时可以顺便删除打了删除标记的点。当被删除结点的个数超过总结点数的(1?α)倍时可以选择重构整棵树进行结构优化,并且显然这部分重构的复杂度不会超过O(nlogn)。

---------------------------------------------------------------------------------------------------------------------------------------------------

——以上内容蒯自xLightGod学长(http://blog.xlightgod.com/%E3%80%90bzoj3224%E3%80%91%E6%99%AE%E9%80%9A%E5%B9%B3%E8%A1%A1%E6%A0%91/)

时间: 2024-08-07 00:17:38

关于平衡树的一些总结的相关文章

bzoj3224 Tyvj 1728 普通平衡树

Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 1. 插入x数 2. 删除x数(若有多个相同的数,因只删除一个) 3. 查询x数的排名(若有多个相同的数,因输出最小的排名) 4. 查询排名为x的数 5. 求x的前驱(前驱定义为小于x,且最大的数) 6. 求x的后继(后继定义为大于x,且最小的数) Input 第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6) Output 对于操作3,4,

bzoj 3224: Tyvj 1728 普通平衡树.

3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 15114  Solved: 6570[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数,因输出最小的排名)4. 查询排名为x的数5. 求x的前驱(前驱定义为

数组splay ------ luogu P3369 【模板】普通平衡树(Treap/SBT)

二次联通门 : luogu P3369 [模板]普通平衡树(Treap/SBT) #include <cstdio> #define Max 100005 #define Inline __attri\ bute__( ( optimize( "-O2" ) ) ) Inline void read (int &now) { now = 0; register char word = getchar (); bool temp = false; while (wor

对于各种各样平衡树的比较

近来闲来无事...难题不会做,简单题不想做... 又不能颓废,于是就去学各种各样的平衡树 故在此对各种平衡树做一些比较(不太常见的, Treap这样烂大街的就不比了) 二次联通门 : 数组splay ------ luogu P3369 [模板]普通平衡树(Treap/SBT) 二次联通门 : 替罪羊树 ------ luogu P3369 [模板]普通平衡树(Treap/SBT) 二次联通门 : 红黑树 ------ luogu P3369 [模板]普通平衡树(Treap/SBT) 评测地址为

平衡树初阶——AVL平衡二叉查找树+三大平衡树(Treap + Splay + SBT)模板【超详解】

平衡树初阶——AVL平衡二叉查找树 一.什么是二叉树 1. 什么是树. 计算机科学里面的树本质是一个树状图.树首先是一个有向无环图,由根节点指向子结点.但是不严格的说,我们也研究无向树.所谓无向树就是将有向树的所有边看成无向边形成的树状图.树是一种递归的数据结构,所以我们研究树也是按照递归的方式去研究的. 2.什么是二叉树. 我们给出二叉树的递归定义如下: (1)空树是一个二叉树. (2)单个节点是一个二叉树. (3)如果一棵树中,以它的左右子节点为根形成的子树都是二叉树,那么这棵树本身也是二叉

【bzoj3224】Tyvj 1728 普通平衡树 平衡树的三种姿势 :splay,Treap,ScapeGoat_Tree

直接上代码 正所谓 人傻自带大常数 平衡树的几种姿势:  AVL Red&Black_Tree 码量爆炸,不常用:SBT 出于各种原因,不常用. 常用: Treap 旋转 基于旋转操作和随机数堆 但不支持区间操作. 非旋转 基于随机数堆和拆分合并操作 常数较大 Spaly 完全基于旋转 各种操作 ScapeGoat_Tree 基于a权值平衡树和压扁重构 无旋转 但不支持区间操作 PS:非旋转可以实现平衡树的可持久化,从而来套一些东西 splay #include<cstdio> #de

Tyvj 1729 文艺平衡树

Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 4604  Solved: 2691[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 Input 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n)  m表示翻转操作

平衡树

首先,我们回顾一下二叉查找树(binary search tree, BST). 二叉查找树具有下列性质: 若左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若右子树不空,则右子树上所有结点的值均大于它的根结点的值: 左.右子树也分别为二叉查找树: BST 的插入 首先执行查找算法,找出被插结点的父亲结点. 若 key 值比当前结点小,则进入左儿子. 若 key 值比当前结点大,则进入右儿子. //在二叉查找树中插入查找关键字key void InsertBST(t,key) { if

BZOJ3196 二逼平衡树

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行有n个数

BZOJ1588: [HNOI2002]营业额统计(正解:平衡树,我的歪解:暴力)

Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额.分析营业情况是一项相当复杂的工作.由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题.经济管理学上定义了一种最小波动值来衡量这种情况: 该天的最小波动值 当最小波动值越大