P3379 【模板】最近公共祖先(LCA)

简介: P3379 【模板】最近公共祖先(LCA)

题目描述

如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。


输入输出格式

输入格式:

第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。


接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。


接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。


输出格式:

输出包含M行,每行包含一个正整数,依次为每一个询问的结果。

求最近公共祖先的方法:1.树剖,2.倍增,3.RMQ,4.tarjan
1.树剖版
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e6 + 5;
int head[maxn], tot;
struct Edge {
    int u, v, next;
}edge[maxn];
int father[maxn], depth[maxn], size[maxn], son[maxn], top[maxn];
int L[maxn], R[maxn], Index;
void init() {
    memset(head, -1, sizeof(head));
    tot = 1;
}
void add(int u, int v) {
    edge[++tot].u = u; edge[tot].v = v;
    edge[tot].next = head[u]; 
    head[u] = tot;
}
void dfs1(int u, int fa) {
    size[u] = 1;
    son[u] = 0;
    father[u] = fa;
    depth[u] = depth[fa] + 1;
    int maxson = -1;
    for (int i = head[u]; i != -1; i = edge[i].next) {
        int to = edge[i].v;
        if (to == fa) {
            continue;
        }
        dfs1(to, u);
        size[u] += size[to];
        if (size[to] > maxson) {
            maxson = size[to];
            son[u] = to;
        }
    }
}
void dfs2(int u, int topf) {
    top[u] = topf;
    L[u] = R[u] = ++Index;
    if (son[u]) {
        dfs2(son[u], topf);
    }
    for (int i = head[u]; i != -1; i = edge[i].next) {
        int to = edge[i].v;
        if (L[to] || to == son[u]) {
            continue;
        }
        dfs2(to, to);
    }
    R[u] = Index;
}
int LCA(int x, int y) {
    while (top[x] != top[y]) {
        if (depth[top[x]] < depth[top[y]]) {
            swap(x, y);
        }
        x = father[top[x]];
    }
    if (depth[x] > depth[y]) {
        return y;
    }
    return x;
}
inline int read() {
    int ans = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        ans = ans * 10 + ch - '0';
        ch = getchar(); 
    }
    return ans;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    init();
    int n, m, s, u, v;
    n = read(); m = read(); s = read();
    for (int i = 1; i <= n - 1; i++) {
        u = read(); v = read();
        add(u, v); add(v, u); 
    }
    dfs1(s, 0);
    dfs2(s, s);
    for (int i = 1; i <= m; i++) {
        u = read(); v = read();
        printf("%d\n", LCA(u, v));
    }
    return 0;
}
相关文章
|
5月前
Luogu P3379 【模板】最近公共祖先(LCA),树链剖分求LCA模板
Luogu P3379 【模板】最近公共祖先(LCA),树链剖分求LCA模板
35 0
|
5月前
|
算法 vr&ar Windows
Tarjan算法求LCA(最近公共祖先)
Tarjan算法求LCA(最近公共祖先)
38 0
|
5月前
【每日一题Day318】LC1123最深叶节点的最近公共祖先 | dfs
【每日一题Day318】LC1123最深叶节点的最近公共祖先 | dfs
33 0
|
11月前
|
算法 C++
最近公共祖先(LCA)
最近公共祖先(LCA)
51 0
LeetCode——根据二叉树创建字符串与二叉树的最近公共祖先
LeetCode——根据二叉树创建字符串与二叉树的最近公共祖先
leetcode236—二叉树的最近公共祖先(递归/深搜/理解)
leetcode236—二叉树的最近公共祖先(递归/深搜/理解)
|
存储 C++
井号法(#)创建二叉树(利用前序遍历来建树)C++实现
井号法(#)创建二叉树(利用前序遍历来建树)C++实现
152 0
井号法(#)创建二叉树(利用前序遍历来建树)C++实现
es 实现二叉树的前序中序,后序遍历,后序中序还原二叉树,前序中序还原二叉树,二叉树的比较diff
es 实现二叉树的前序中序,后序遍历,后序中序还原二叉树,前序中序还原二叉树,二叉树的比较diff
es 实现二叉树的前序中序,后序遍历,后序中序还原二叉树,前序中序还原二叉树,二叉树的比较diff
二叉树的三种非递归遍历方式
二叉树的三种非递归遍历方式
|
算法 Java C++
LeetCode(算法)- 236. 二叉树的最近公共祖先
LeetCode(算法)- 236. 二叉树的最近公共祖先
123 0