【动态树初探】link-cut tree

来源:互联网 发布:串行接口编程 c语言 编辑:程序博客网 时间:2024/06/04 18:12

很愚昧的以为动态树是一种数据结构,现在才知道动态树是是一类问题(Dynamic Tree Problems)。

 

spoj上有一系列关于树的很有趣的题目(qtree1~4),和树链剖分、动态树有关,所以就狠下心的研究了一番,多亏找到了一篇好论文《qtree解法的一些研究 by yangzhe》,解决动态树问题的数据结构叫link-cut tree(又是tarjan发明的,无限崇拜!!),看懂了思想以后便抱着视死如归的心态编了起来(拿hnoi2010的bounce来练手),因为看了标程,7kb、8kb、7kb,=、=。

 

首先说说树链剖分,差不多就是link-cut tree 的静态版(静态树!?),前提是树的形状不发生改变。树中的重边的定义就是每个点向他最大的儿子(子树大小最大)连的边,其他的边就是轻边。可以证明一个点到根节点经过的轻边数不超过logN,证明:

      定义size(i)为以i为根的子树大小,

      若 i 和 fa(i) 之间连的是轻边

      也就是 存在  j∈son(fa(i)),size(j)≥size(i)

      又∵ size(fa(i))≥size(i)+size(j),

      ∴size(fa(i))>2*size(i).

每走一条轻边节点数都会增大一倍,那当然不可能超过logN条轻边咯。

 

对于一串连续的重边,我们就把它压缩为一条重路径。

如果这棵树的形状不改变,那么重路径自然也不会发生变化,那我们可以用线段树或者是虚二叉树来维护,若会改变,则用splay tree维护(以深度为关键字)。

 

在实际link-cut tree的编写中并不要考虑谁是重边谁是轻边,假设你访问了某一个点,就把它到父亲的边全改为重边就可以了,可以证明也是logN的(证明有点懵。。)。

 

回顾hnoi2010的弹飞绵羊,这正是一个动态树问题(哎,我靠怎么那时候不会捏?),要求支持这样两个操作:

      1.询问某个点的深度。

      2.改变某个点的父亲。

 

记得之前用块状链表水过了,速度还不错,不过看来 link-cut tree 还是以绝对优势压倒了:

 

块状链表:

块状链表

 

link-cut tree

link-cut

 

这次还给了我一个教训,不要被标程吓到了。。。可能牛们为了让人更容易看懂才编长一点的吧,却着实把我这种小白吓到了。。。

自己编起来感觉也很舒服,74行,主要注意的还是旋转时候的父亲的转化。

(裸的splay不解释。。。都是想想写写胡编乱抽的)代码:

 

 

原创粉丝点击