倍增\ tarjan求lca

对于每个节点v,记录anc[v][k],表示从它向上走2k步后到达的节点(如果越过了根节点,那么anc[v][k]就是根节点)。

dfs函数对树进行的dfs,先求出anc[v][0],再利用anc[v][k] = anc[anc[v][k - 1]][k - 1]  (从v向上2k步即为从v向上2(k - 1)步再向上2(k - 1)步)

求出其他anc[v][k]的值

lca(u, v)函数寻找u和v的lca, 首先把u和v调整到一个高度。如果此时u和v重合,那么这就是我们要找的lca,如果他们补充和,就不断的寻找一个最小的k,使得

anc[u][k] = anc[v][k]

 

复制代码
int anc[maxn][20], deep[maxn];

int dfs(int u, int fa)
{
    for(int i = 1; i < 20; i++)
        anc[u][i] = anc[anc[u][i - 1]][i - 1];
    for(int i = head2[u]; i != -1; i = Edge[i].next)
    {
        int v = Edge[i].v;
        if(v == fa || deep[v]) continue;
        anc[v][0] = u;
        deep[v] = deep[u] + 1;
        dfs(v, u);
    }
}

int lca(int u, int v)
{
    if(deep[u] < deep[v]) swap(u, v);
    for(int i = 20 - 1; i >= 0; i--)
        if(deep[anc[u][i]] >= deep[v])
            u = anc[u][i];

    for(int i = 20 - 1; i >= 0; i--)
    {
        if(anc[u][i] != anc[v][i])
        {
            u = anc[u][i];
            v = anc[v][i];
        }
    }
    if(u == v) return u;
    return anc[u][0];
}
复制代码

 

 

tarjan求lca  

1.任选一个点为根节点,从根节点开始。

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

3.若是v还有子节点,返回2,否则下一步。

4.合并v到u上。

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

合并就用并查集就好了

 

板子先欠着

 

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

posted @   WTSRUVF  阅读(150)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示