此题乃传说中splay的简单应用。
不愧是传说中的数据结构,花了两天才写出来,第一次写debug可是费了不少功夫啊。
老实说写这种数据结构还真是不简单,上次学treap的时候也是花了好大功夫。
不过最终好歹是写出来了,而且学到了不少东西。算是值了。
上次写treap的时候,旋转操作写了两个函数,这次学会了一种新写法,可以将旋转操作直接写成一个函数。
在结构体中 用ch[2] 来记录儿子节点。
用ch[0]表示左儿子,用ch[1]表示右儿子。
于是rotate操作就可以写成
其中s=0 表示x节点是其父节点的左儿子 s=1则表示x是其父节点的右儿子
这样一来两种旋转操作就可以用一个函数搞定了。
至于伸展树的核心操作splay(int x,int f) 将x节点旋转到f节点的下方。则是两种原始旋转操作的组合,注意一字型旋转和之字型旋转时,旋转节点的顺序就行了。
有一种写法很不容易想到,就是标记法。
比如 将某一区间的数字反转,我们再提取该区间后,不用马上将该区间所有数进行反转操作,只需用一个标记标记该区间在访问时候需要反转。 这样的话,可以省很多时间。因为不访问时,进行反转操作是没有必要的。 比如在该区间被访问之前需要经历2×n次反转,那么实际上该区间最后的效果是不需要反转,我们只要修改标记就可以达到这个效果;
当访问到该区间时,我们对该节点执行标记的相应操作,然后将标记下移即可。
如果写过线段树的话,这点应该很容易理解了。
如果想学习splay ,可以看看杨思雨的论文,baidu一下就出来了
贴下我自己的代码吧:
跑了600多MS,写的挺一般的。