最近学习了一下各种BBST,简单总结一下。
Splay Tree:区间操作强无敌…对[l,r)区间的操作,把l-1结点splay到树根,r结点splay到根的右结点,则根的右结点的左子树就是区间[l,r),然后对这棵子树进行操作。一个splay操作的均摊复杂度为O(logn)。
常见操作:[l,r)区间每个数加a,每个结点维护一个加的数值的lazy_tag
[l,r)区间翻转,每个结点维护一个表示是否翻转的标记
在第k个元素后插入元素或区间,若是区间,则要先建成一棵bst,把第k个结点splay到树根,第k+1个结点splay到根的右孩子,把需要插入的子树接到右孩子的左孩子。
删除元素,得到区间[l,r)后摘除子树。
实现:刚开始看时还纳闷为什么在实现时都要先加根节点以及根节点的右孩子,然后把整个区间建在根的右孩子的左子树上。后来才想到对于整个区间[1,N+1),这种做法相当于在开始和结尾各添加一个元素,对整个区间进行操作则需要把这两个结点splay到树根和根的右孩子,才能得到整个区间。在第一个元素前和最后一个元素后插入都需要借助这两个结点。
ref: https://zhuanlan.zhihu.com/p/32090049?iam=5a347fde94eade0536f38c5e7434e822
http://blog.csdn.net/acm_cxlove/article/details/7800979
1 | HDU 3487 Play With Chain |
1 | POJ 3580 SuperMemo |
Treap:BST+heap,每个结点维护两个属性key,priority,结点的key满足bst,left.key<x.key<right.key;priority满足heap的性质,x.priority<child.priority(若min heap)。相当于是首先把所有结点按照priority的大小从小到大排序,然后按照排序后的顺序依次插入bst。结点的priority是随机的,整个按照priority排序的序列相当于一个随机的序列,因n个关键字随机插入所构建的bst的高度期望是O(logn),treap的高度的期望也是O(logn)。
一般treap可用来维护一个序列,给定x,查询x在序列排序后的位置;或给定位置k,查询元素x
1 | POJ 1442 Black Box |
AVL Tree:nice的结构,在插入删除时进行旋转操作保证左右树高差不超过1
旋转操作比较复杂,总结一下即左高时右旋,若左子树右高,则左子树先左旋;右高时左旋,若右子树左高,则右子树先右旋。
AVL树与Treap一样都是用来实现BBST,还有红黑树,不过实现就有点复杂了。
1 | SPOJ AVL Tree |