LCA (Tarjan&倍增)

Posted l999q

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LCA (Tarjan&倍增)相关的知识,希望对你有一定的参考价值。

LCA_Tarjan

参考博客:https://www.cnblogs.com/JVxie/p/4854719.html

LCA的Tarjan写法需要结合并查集

从叶子节点往上并

int Find (int x) 
    return x == pre[x] ? x:pre[x] = Find(pre[x]);

void dfs(int x,int w,int fa) 
    d[x] = w;    //点x的深度
    //遍历与点x相连的点(除了已经访问过的和其父节点)
    for (int i = 0; i < v[x].size(); i++) 
        if (!vis[v[x][i]] && v[x][i] != fa) 
            dfs(v[x][i],w+1,x);
            pre[v[x][i]] = x;
            vis[v[x][i]] = 1;
        
    
    //访问所有和x有询问关系的e
    //如果e被访问过;
   //x,e的最近公共祖先为find(e);

 

LCA_倍增

  参考博客:https://www.cnblogs.com/zhouzhendong/p/7256007.html

  先写暴力写法:当x,y深度不同时先把深的调到和浅的同一深度再一起往前面跳找其最近公共祖先。

void dfs(int f,int u)
    fa[u]=f;
    d[u]=d[f]+1;
    for (int i=0;i<v[u].size();i++)
        if (v[u][i]!=f) dfs(u,v[u][i]);

int LCA(int a,int b)
    if (d[a]>d[b])
        swap(a,b);
    while (d[b]>d[a]) b=fa[b];
    while (a!=b) a=fa[a],b=fa[b];
    return a;

  显然,一个一个的跳太慢了,我们可以考虑通过二进制进行优化,也就是倍增。

void dfs(int f,int u) 
    fa[u][0] = f;
    dep[u] = dep[f] + 1;
    for (int i = 1; i <= 15; i++) 
        fa[u][i] = fa[fa[u][i-1]][i-1];
        //其他操作
    
    for (int i = 0; i < v[u].size(); i++) 
        if (f == v[u][i]) continue;
        dfs(u,v[u][i]);
    

void lca(int x,int y) 
    memset(ans,0,sizeof(ans));
    if (dep[x] < dep[y]) swap(x,y);
    for (int i = 15; i >= 0; i--) 
        if (dep[fa[x][i]] >= dep[y]) 
            //其他操作
            x = fa[x][i];
        
    if (x == y) 
        return;
    
    for (int i = 15; i >= 0; i--) 
        if (fa[x][i] != fa[y][i]) 
            //其他操作
            x = fa[x][i],y = fa[y][i];
        

例题:洛谷P3292 [SCOI2016]幸运数字  | 题解

 

以上是关于LCA (Tarjan&倍增)的主要内容,如果未能解决你的问题,请参考以下文章

LCA算法_普通做法&倍增&Tarjan&RMQ

tarjan,树剖,倍增求lca

LCA[倍增][树剖][tarjan]

倍增 Tarjan 求LCA

两种lca的求法:树上倍增,tarjan

[Nowcoder] network | Tarjan 边双连通分量 | 缩点 | LCA倍增优化 | 并查集