浅谈Tarjan——5(用Tarjan求LCA)

Tarjan算法不仅可以用来缩点,还可以用来求LCA。

先介绍一下LCA,LCA(least common ancestors),是最近公共祖先的英文。指的是在一棵树中,点u和点v的最近的祖先。这里写图片描述
如图,以黄点为树根:紫点和黑点的最近公共祖先就是绿点,白点和橙点的最近公共祖先就是橙点,灰点和蓝点的最近公共祖先是黄点。简而言之,LCA就是点u和v的父亲的父亲的父亲……第一个相交的父亲。

LCA的算法有很多,例如倍增RMQ,树剖。用Tarjan算法来求LCA,理论上时间复杂度为(N+Q),但在实际操作中会稍稍慢一些。Tarjan求LCA是一个离线算法,并基于并查集(union-find-set)。

我们用vis记录该点是否被访问过,fa记录该点的父亲,从根节点向下搜索,遍历每一个儿子。如果它的儿子全都遍历完了,就去查询与该点有关的点,也就是所查询的点组中有该点的那些组,如果另一个点v已经被访问过,那么这两个点的最近公共祖先就是find(v),否则先不记录。(证明略)
基本思路就是这五步:

1.从根节点开始搜索。

2.遍历该点u所有子节点v,并标记这些子节点v已被访问过。

3.若是v还有子节点,遍历v的子节点,否则合并u,v。

4.寻找与当前点u有询问关系的点v。

5.若是v已经被访问过了,则可以确认u和v的最近公共祖先为v被合并到的父亲节点a。
伪代码:

void lca(int x){
    now[x]=1;
    for x的所有儿子{
        lca(v);
        vis[v]=1;fa[v]=x; 
    }
    for 与x有关的查询
        if(vis[v])
          ans=find(v);
}

模板:

void lca(int x){
    now[x]=1;
    for(int i=0;i<f[x].size();i++){
        int go=f[x][i];
        if(now[go]) continue;
        lca(go);
        vis[go]=1;fa[go]=x; 
    }
    for(int i=0;i<query[x].size();i++){
        int go=query[x][i];
        if(vis[go]) ans=find(go);
    }
}

详细模拟过程点这里,这位神犇写的很好


2018.5.25更新:
这里再谈谈LCA,一般来说LCA有四种求法:在线ST表,在线倍增,在线树剖和离线Tarjan。
离线Tarjan这里已经详细地讲述了,ST表和倍增算法是比较普遍的算法,这些算法网上都有详细的讲解,这里就贴一个倍增求LCA的函数:
int lca(int x,int y){
    register int i;
    if(dep[x]>dep[y]) swap(x,y);
    for(i=19;i>=0;i--)
      if(dep[x]<=dep[gran[y][i]]) y=gran[y][i];
    for(i=19;i>=0;i--)
      if(gran[x][i]!=gran[y][i]) x=gran[x][i],y=gran[y][i];
    if(x!=y) y=gran[y][0];
    return y;
}
这里主要讲一讲树剖的方法,由于树剖维护了重链,所以每一次重链顶较深的点往上跳,直跳到两个点在同一个链上,则此时深度较小的点就是LCA。
int LCA(int x,int y){
    while(top[x]!=top[y]){
        if(dep[top[x]]>dep[top[y]]) swap(x,y);
        y=fa[top[y]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    return x;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值