用于仙人掌的top trees

用于仙人掌的top trees

众所周知,top trees是一种用于解决动态树问题的数据结构.它的通用性十分强,不仅能处理通常的动态树操作和路径/树上数据的操作,还允许分治统计信息(相当于QTREE系列的动态版)、进行non-local search(查询树上一些有特殊性质的边)(可以用 O(\log n) 时间找到重心),应用十分广泛.

如果需要了解更多,这里的资料可能会有一点用..


前置技能:top trees.是真正的那种,不是那个魔改数据结构..


(下面提到的路径都是指简单路径)

现在我们考虑将其推广用于“动态仙人掌问题”,即维护若干个不相交仙人掌组成的图,支持加边、删边、修改/查询两点之间[最短路径/最长路径/所有路径的并]或整个仙人掌上的信息.

既然想用在仙人掌上,就得先定义“仙人掌收缩”.显然树收缩的操作是不够的,因为无法解决环的问题.

我们需要引入第三种操作,把两条端点相同的边合并为一条.我把这操作称为twist<del>,后来发现25年前就有人这样叫了</del>..

(这样画没问题吧..)

相应地,top tree中也会出现一种结点:twist结点,两个孩子表示原来的两条边.

图中用八边形表示twist结点.(画完才发现rake结点太少了只有1个..不过应该没什么大问题)

容易知道,这样仍能保证存在 O(\log n) 层的收缩.很多信息仍然能在twist结点上统计,于是只要能用 O(\log n) 时间完成link、cut、expose,那么很多动态树上的操作仍然可以在动态仙人掌进行.


下面给出一个self-adjusting版本的实现.


前置技能:self-adjusting top trees.(树上的都没学咋学仙人掌上的..)


和Tarjan的论文一样,下面默认边按照某种顺序在点周围,并需要维护这个顺序..实际中需要这个顺序的可能并不多,以下的某些东西可以大大简化


类似用于树的self-adjusting top trees,我们对仙人掌进行剖分,但不是剖分为路径,而是某两点间所有路径的并.对于这样“带环的路径”(这东西有没有什么名字啊),我们把每个环上离路径某个端点最近的点称为这个环的端点,环的两个端点把环分为两条边不相交的路径.我们对环的两条路径分别进行compress(用一个compress tree表示),再twist为一条边,这样整条“带环的路径”就被收缩为一条路径,直接用compress tree维护即可.

注意到如果要维护边的顺序,还需要处理环的两个端点在环内的子树.类似compress,这可以在twist之前进行rake,并成为twist结点的两个foster child.然而,并不能expose环内和环外的顶点,因为twist的两条边之间不能有其他边,这只能通过将这些边rake到环上做到.

Expose操作和树上的情形相似,只需要再考虑如何解决splice到环上的情形.这种情形会改变环的端点,与非环上的splice相比,我们还需要先对环的两个原端点进行local splay.

同样我们还需要考虑怎么进行和环相关的link/cut操作.显然可以先进行 soft\_expose(u, w) ,对于 link(v, w) 加入一个twist结点 (u, v) 和一个base结点 (u, v) ,对于 cut(v, w) 则相反.



Splice次数仍然是均摊 O(\log n) 的,splay的复杂度分析和树上的情形相似.每次操作仍花费均摊 O(\log n) 时间,常数略大一些,实际应用中通常也是不满的.


(看起来复杂度证明得坑一段时间了..不过去掉rake tree结构的复杂度还是很好证的


这样,我们不仅可以能做QTREE系列加上link和cut,还能丢到仙人掌上..

至于non-local search?..很多东西应该还是能做的..


如果不需要记录边的顺序,可以使用三叉树,twist结点只需记录2个孩子.

如果不需要自顶向下访问,可以用类似ST-trees的方法省略rake结点.


(拿这种东西出比赛题是会被打死的


Open Problems:

用于仙人掌的worst-case top trees?

能否进一步将top trees推广到其他有特殊性质的图上?

编辑于 2018-07-04

文章被以下专栏收录