LCA问题

在一棵有根树中,两个结点u和v的最近公共祖先是指这样的一个结点 w,是u和v的祖先,并且在树T中具有最在深度。

tarjan离线算法 ,伪代码如下:

LCA(u)

     MAKE-SET(u)

     ancestor[FIND-SET(u)] = u

     for each child v of u in T

          LCA(v)

          UNION(u,v)

          ancestor[FIND-SET(u)]=u

     color[u] = BLACK

     for each node v such that [u,v] 属于P

          if color[v] = BLACK

               print "The least common ancestor of " u "and" v "is" ancestor[FIND-SET(v)]

平方根分段法

将高度为h的树分成sqrt(h)段,用P(x)来表示结点x的祖先结点,将第一段中的所有结点P(x)设置为根结点(根结点标号为1),从第二段开始,每段的第一层,即上图中的结点5,6,7,12,13的P(x)设置为x的父结点,其它层结点上的P(x)设置为P(x的父结点)。对于查询LCA(x,y),先调整P(x)和P(y),使得在同一段,然后根据其结点所在的深度,向上转直到x,y 的父结点相等。在使用DFS遍历得到深度及父结点关系,P(x)关系时,时间复杂度为O(n),在查询时时间复杂度为O(sqrt(n))。其伪代码如下

function dfs(u, father, depth)

    parent[u] = father

    height[u] = depth

    for v on edge [u,v]

         if v != father

             dfs(v, u, depth + 1)

function calP(u, father, sections)

    if height[u] < sections

        P(u)= 1

    else if height[u] % sections == 0)

        P(u) = parent[u]

    else 

       P(u) = P(parent[u])

    for v on edge [u,v]

         if v != father

              calP(v, u, sections)

function LCA(u,v)

       while (P(u) != P(v))

              if (height(u) < height(v))

                    v = P(v)

             else 

                    u = P(u)

        while (u != v)

                if (height(u) < height(v))

                     v = parent(v)

                else 

                     u = parent(u)

树上倍增算法 :

与上面方法有些类似。用st[i][j]表示结点i的第2^j个祖先结点,有st[i][j] = st[st[i][j-1]][j-1]。在求LCA(u,v)时,将深度深的移动到深度浅的,即在height(u)>height(v)时,将u移动height(u)-height(v)次,移动相同深度位置,然后再同步上移。算法如下:

LCA(u,v)

      if height(u) > height(v)

            swap(u,v)

      h = height(v)-height(u)

      for i in 0 to maxlog

            if h & (1 <<i)

                v = st[v][i]

      if u ==v 

           return

      for i in maxlog to 0

           if st[u][i] != st[v][i]

               u = st[u][i]

               v = st[v][i]

      return parent[u]

RMQ算法

通过对根深度优先搜索得到欧拉序用E[0,2n-1]表示,L[i]表示结点E[i]的深度,用R[i]表示 E中第一次出现i的位置。LCA(u,v)=RMQ(L, R(u), R(v)),通过 sparse table来计算区间最值,时间复杂度为O(nlogn),查询时间复杂度为O(1).

参考资料:

https://www.topcoder.com/community/competitive-programming/tutorials/range-minimum-query-and-lowest-common-ancestor/#Lowest%20Common%20Ancestor%20(LCA)

http://cp-algorithms.com/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kgduu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值