世界真的很大
SPLAY是个很厉害的数据结构,相对于其他平衡树,比如treap,对于每一次查询虽然常数偏大,但是却能力保总复杂度趋近于nlogn,而且除了treap能支持的操作以外,还支持如区间翻转一类的特殊操作
其关键在于其独属的SPLAY操作
所以这次更多的是对SPLAY的一个详细总结
好像也是tarjan发明的,orz
看题先:
description:
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1
input
第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n) m表示翻转操作次数
接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n
output
输出一行n个数字,表示原始序列经过m次变换后的结果
题面还是比较良心的
看上去只需要一种操作,就是区间翻转,但是其他数据结构好像不是很好维护这个操作
首先谈谈SPLAY是一个什么东西
SPLAY首先是一颗BST,它有着BST共有的性质,即满足左小右大的性质,而旋转是BST几乎共有的一种操作,旨在不破坏BST性质的情况下调整树的结构
中序遍历是一种树的遍历方式,只要树是BST,那中序遍历的节点顺序就不会改变。因为中序遍历是左中右的顺序,而BST满足左小右大的性质,对于任意一个点,比他小的点在不修改的前提下是固定的,所以中序遍历的结果也不会改变
SPLAY的核心操作就是SPLAY,它的意思是将某一个节点通过旋转的方式,不破坏BST,到达指定位置。但指定位置一定得在它上面。这么做的目的是使得被多次访问的点尽可能的靠近根节点,这样在后续访问过程中使得访问尽量短,虽然每次访问会多了将访问节点旋转到根的时间,但却使后续对相同节点的访问时间缩短,从而使时间复杂度“平摊”,确保总操作复杂度趋于稳定。
而实现的方法其实也相对简单,就是旋转
如果目标节点就是当前节点的父亲,那直接旋转便是
否则采用双旋的办法,往上跳。
双旋右分2种
一种是当前节点的父亲,和当前节点父亲的父亲,也就是爷爷,三者形成了链式结构,就是说父亲是爷爷的左儿子,儿子也是父亲的做儿子,或者父亲是爷爷的右儿子,