倍增算法 最近公共祖先(LCA)C++

倍增算法(Binary Lifting)是一种用于解决最近公共祖先(LCA)问题的算法。

最近公共祖先问题是指在一棵有根树中,给定两个节点,找到它们的最近公共祖先节点。最近公共祖先节点是指在树中同时是这两个节点的祖先节点,并且离这两个节点的距离最近。

倍增算法的核心思想是在树的深度方向上使用二进制的方式进行跳跃。具体步骤如下:

  1. 预处理:对于每个节点,计算它的2^i级祖先节点,其中i从0开始递增。这可以通过自底向上的动态规划来实现。第一级祖先节点是每个节点的父节点,第二级祖先节点是每个节点的父节点的父节点,以此类推。

  2. 查询:给定两个节点x和y,首先判断它们的深度d,将深度较大的节点向上移动到与另一个节点处于同一深度。然后,从最大的2^i开始,每次向上跳跃2^i个级别,直到两个节点达到同一级别。在跳跃过程中,每次都检查是否达到了公共祖先节点。每个节点跳跃的级别数取决于两个节点的深度差。

倍增算法的时间复杂度为O(log n),其中n为树的节点数。预处理需要O(n log n)的时间来计算每个节点的祖先节点,查询阶段需要O(log n)的时间来计算最近公共祖先节点。空间复杂度为O(n log n),用于存储每个节点的祖先节点。

复制代码
#include <bits/stdc++.h>
#define ll long long
#define endl "\n"
#define KUI ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
const int con = 5e5 + 5;
const int mod = 998244353;
int n, m, s, k, dep[con], fa[con][20];
vector<int> v[con];
void dfs(int u, int f)
{
    dep[u] = dep[f] + 1;
    fa[u][0] = f;
    for (int i = 1; i <= 19; i++)
    {
        fa[u][i] = fa[fa[u][i - 1]][i - 1];
    }
    for (int v : v[u])
    {
        if (v != f)
        {
            dfs(v, u);
        }
    }
}
int lca(int u, int v)
{
    if (dep[u] < dep[v])
    {
        swap(u, v);
    }
    for (int i = 19; i >= 0; i--)
    {
        if (dep[fa[u][i]] >= dep[v])
        {
            u = fa[u][i];
        }
    }
    if (u == v)
    {
        return v;
    }
    for (int i = 19; i >= 0; i--)
    {
        if (fa[u][i] != fa[v][i])
        {
            u = fa[u][i], v = fa[v][i];
        }
    }
    return fa[u][0];
}
int main()
{
    KUI;
    cin >> n >> m >> s;
    for (int i = 1; i <= n - 1; i++)
    {
        int a1, a2;
        cin >> a1 >> a2;
        v[a1].push_back(a2);
        v[a2].push_back(a1);
    }
    dfs(s, 0);
    for (int i = 1; i <= m; i++)
    {
        int a1, a2;
        cin >> a1 >> a2;
        cout << lca(a1, a2) << endl;
    }
    return 0;
}
相关推荐
西柚小萌新2 分钟前
【计算机视觉CV:目标检测】--3.算法原理(SPPNet、Fast R-CNN、Faster R-CNN)
算法·目标检测·计算机视觉
_Kayo_3 分钟前
Node.JS 学习笔记8
笔记·学习·node.js
知识分享小能手4 分钟前
Oracle 19c入门学习教程,从入门到精通,Oracle 数据表对象 —— 语法知识点详解与案例实践(10)
数据库·学习·oracle
高频交易dragon4 分钟前
Hawkes LOB Market从论文到生产
人工智能·算法·金融
脏脏a5 分钟前
C++ 容器的两把利器:优先级队列与反向迭代器
c++·反向迭代器·优先级队列
历程里程碑6 分钟前
Linux 2 指令(2)进阶:内置与外置命令解析
linux·运维·服务器·c语言·开发语言·数据结构·ubuntu
王燕龙(大卫)9 分钟前
rust入门
开发语言·rust
无心水10 分钟前
2、Go语言源码文件组织与命令源码文件实战指南
开发语言·人工智能·后端·机器学习·golang·go·gopath
2501_9445264211 分钟前
Flutter for OpenHarmony 万能游戏库App实战 - 主题切换实现
android·开发语言·javascript·python·flutter·游戏·django
张张努力变强12 分钟前
C++ 类和对象(三):拷贝构造函数与赋值运算符重载之核心实现
开发语言·c++