查找树的LCA(Least Common Ancestor)算法

前言

Euler Tour of A Tree

ETT即Euler-Tour-Tree,也就是采用欧拉序来访问一棵有n个node的树,例如上图所示的这棵树,欧拉序为:9 2 1 7 1 8 1 2 4 2 6 2 9 3 9 5 9;即从根节点开始,dfs(深度优先遍历,前序遍历)依次输出访问边对应的节点,Euler Tour的长度是2n-1,因为每次遍历一条边时输出一个节点,遍历了n-1条边两次,每个方向一次。这样的好处是,可以通过欧拉序列知道所有子树的信息,比如以1为根节点的子树就包括 (1 7 1 8  1),1、7和8这3个节点;还可以快速得到根节点:(7 1 8)序列中层数最浅的是1,说明1为该子树的根节点。

RMQ(Range Minimum Query)

RMQ范围最小值查找就是给定一个数组,找到该范围内最小元素的索引。LCA问题可以规约为RMQ问题。

LCA

Naive Algorithm

(1)用数组E\left [ 1,...,2n-1 \right ]来按顺序存储Euler Tour访问的节点;

(2)用数组L\left[1,...,2n-1 \right ]存储E\left[i \right ]对应节点的高度(即节点到根节点的距离);

(3)用数组R\left[1,...,n \right ]存储每个节点i在Euler Tour中第一次出现的索引,即argmin_{j}\left \{ E\left[j \right ] =i\right \};

(4)两个节点u,v第一次出现之间访问的节点为E\left[R[u]],...,R[v] \right ]或者E\left[R[v]],...,R[u] \right ],在这个子序列中最浅的节点即高度最小的就是u,v的LCA,即RMQ_{L}\left(R[u],R[v] \right )

该方法预处理阶段的时间复杂度为O(n^{2}),差不多是暴力解法。

Faster RMQ Algorithm

思想——用一个二维表M来提前将RMQ的最小值计算并进行存储。

(1)对于每一个i(1\leqslant i\leqslant n)j(1\leqslant j\leqslant logn),找到区块\left[i,i+2^{j} \right]的最小的元素并存储在M中,即M[i,j]=argmin_{k=i...i+2^{j}-1}\left\{A[k]\right\},表M的大小为O(nlogn)

(2)使用dynamic programming(DP思想)填满M只需要O(nlogn)的时间复杂度:对于2^{j}大小的block,只需计算其两个连续子block的最小值,即M[i,j]=min(M[i,j-1],M[i+2^{j}-1,j-1])

(3)即使用Sparse Table(ST)来计算RMQ,并需要类似找the most significant bit of a word的操作。

(4)查询:我们需要两个已知的固定区间,能够覆盖(可以重合一部分)整个查询区间。为了方便查找,我们规定这两个已知区间覆盖的区间长度均为2^k,并且两个区间分别有一端为L和R。那么随着这个k不断增大,一定存在一个临界点k,刚好覆盖(或最少重合)这个区间。当k满足题意时,两个区间分别为[L,L+2k−1][L,L+2k−1]和[R−(2k−1),R][R−(2k−1),R],此时只需要满足R−(2k−1)≤L+2k−1R−(2k−1)≤L+2k−1即可,化简之后推出公式:R−L+2≤2k+1,k≥log2(R−L+2)−1。

Fast Algorithm for \pm 1 RMQ

思想——基于\pm 1限制,使用查表方法提前计算小数组的答案,来消除log。\pm 1指任何邻接的两个节点间的高度差为1或-1.

(1)将数组A按每个block大小为\frac{logn}{2}进行划分,得到A^{'}[1,...2n/logn];

(2)定义一个等大的数组B,B[i]表示第i个block里最小元素出现的位置;

(3)查询:当查询的起点ij不在一个block里时,1)找到从ii所在的block里最后一个元素的最小值;2)查找ij之间所有block的最小值;3)查找从j所在block起始位置到j的最小值。

(4)in-block查询优化:对于(3)中的2)的值可以使用ST表实现常数时间复杂度的查询,因此现在主要是优化1)和3)的in-block查询。使用Normalized Block,即依次处理每个block中元素将其将去最初的每个元素,那么对于长度为\frac{logn}{2}的block,共由2^{1/2\cdot logn-1}=O(\sqrt{n})种不同的Normalized Blocks。其余相同的Normalzed Block可以使用相同的预处理,这大大提高了预处理时间。

(5)创建O(\sqrt{n})个table,每个table对应一种Normalized Block。每个Block中保存(\frac{logn}{2})^{2}=O(log^{2}n)种查询结果。

[References]:

M. A. Bender and M. Farach-Colton. The lca problem revisited. In Proc. of LASTI’00, pages 88–94, 2000.

https://blog.csdn.net/Kanosword/article/details/52659924

https://github.com/leifwalsh/rmq

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值