原来听说过可持久化treap,觉得最多就和可持久化线段树一般可用程度。于是对于区间和序列问题就选择使用线段树和splay了,集合问题就选择各种平衡树和Splay。。。然后仔细的看了一下可持久化treap的操作和《范浩强谈数据结构》的ppt,发现这个神一般的既好写(zuo)又好看(wen)还好用(chi)的数据结构。
首先这个东西很好写,作为一个平衡树,它没有旋转!!!是的,一点都没有旋转,rightturn,leftturn什么的去死吧,我们不需要旋转。最基本的操作只有两种,一种叫merge,一种叫split,merge是把两个序列合并的操作,需要保证左边的所有元素小于(广义的小于,根据平衡树的作用来确定)右边的元素,合并时,treap的堆权值(我叫它key,但好像有人叫weight还有其他什么的,还是叫做堆权值一点歧义都没有)要求被维护,则递归调用merge,如果现在的左树堆权值小于右树(假设是小根堆)则调用merge(左树->rson,右树),返回值(node*)作为新节点的右子树,就是在左树的右子树插入右树,因为右树大于左树,所以不会在左树的左子树递归调用,如果左树堆权值大于右树,则调用merge(左树,右树->lson),返回值作为新节点的左子树,新节点的其他值等于原来的左树根或者右树根(具体是哪一个很好思考对吧,balbala就是这样),然后返回这个新节点,注意一个hui常重要的地huang,返回的是新节点!也就是说每次merge其实新建了一条logN的链,所以说为什么叫可持久化treap呢,就是这个原因,只需要把每次操作的返回值存起来,就可以访问历史记录了!Split操作是把一棵树按权值分为两棵,可以写两个函数分别返回左边和右边,这个也需要递归调用,大体思想是如果现在这个节点的权值与分割权值差的很远(这是口头表达)就递归调用下一层,否则新建一个节点,左右子树中和分离无关系的直接挂上去,另一边调用下一层split,然后返回这个新节点。然后,什么基本操作都写好啦,没有turn,没有什么zig-zag。
有了基础操作,怎么insert和delete呢?很简单,insert就是把原树按新节点权值split成两个,merge新节点和左边,merge现在的左边和右边,搞定!还是没有旋转!
delete差不多,split,split,然后不管(Delete)中间那单个元素,merge左右两边,搞定了,也没有旋转!
如果仅仅是这样也不是很神,似乎splay可以进行序列操作。当然,可持久化treap也有,都有split和merge了还有什么不能干?把各种标记往节点上方就行了,几乎和splay一样(当然基础操作不一样),还有,Splay不能做到可持久化(为什么?fhq大神原话:”不可以,因为势能分析失效了!“,什么意思啊?我也不知道。。。),但是可持久化treap就可以!还有线段树,朱(主)熹(席)树啥的不都可以用这个搞定吗?
代码没有,相信所有人都会很容易的写出来!这个神一般的数据结构--可持久化treap。