倍增法求LCA

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e5 + 20;
vector<int>e[N];
int dep[N], fa[N][25];
void dfs(int x, int f)
{
    int siz = e[x].size();
    for (int i = 0; i < siz; i++)
    {
        int to = e[x][i];
        if (to == f) //无向树 防止死循环
            continue;
        dep[to] = dep[x] + 1;
        fa[to][0] = x;
        dfs(to, x);
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int n, m, s;
    cin >> n >> m >> s;
    for (int i = 1; i <= n - 1; i++)
    {
        int x, y;
        cin >> x >> y;
        e[x].push_back(y);
        e[y].push_back(x);
    }
    dfs(s, 0);//求每个节点的深度 根为0
    //预处理每个节点的fa数组
    for (int j = 1; j <= 19; j++)
    {
        for (int i = 1; i <= n; i++)
        {
            int y = fa[i][j - 1];//中间点
            fa[i][j] = fa[y][j - 1];
        }
    }
    while (m--)
    {
        int a, b;
        cin >> a >> b;
        //1.跳到同一高度
        if (dep[a] > dep[b])
        {
            swap(a, b);
        }
        //保证 a在上面让b和a跳到同一高度
        int x = dep[b] - dep[a];
        //b往上跳x步
        for (int i = 19; i >= 0; i--)
        {
            //2^19>5e5
            if ((x >> i) & 1)
            {
                //二进制拆分
                b = fa[b][i];//b往上跳2^i步
            }
        }
        if (a == b)
        {
            //同一高度时已经相遇
            cout << a << '\n';
        }
        else
        {
            //跳到LCA的前一步
            for (int i = 19; i >= 0; i--)
            {
                if (fa[a][i] == fa[b][i])//能跳一起则不跳
                    continue;
                else
                {
                    a = fa[a][i]; b = fa[b][i];
                    //不能跳一起则跳
                }
            }
            cout << fa[a][0] << '\n';
        }
    }
    return 0;
}
posted @ 2024-12-02 20:39  闫柏军  阅读(4)  评论(0编辑  收藏  举报