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

输入输出格式
输入格式:
第一行包含三个正整数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;
}

2.倍增
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5;
vector<int> vec[maxn + 5];
int lg[maxn + 5];
int depth[maxn + 5];
int father[maxn + 5][22];
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;
}
void dfs(int nowp, int fa) {
    depth[nowp] = depth[fa] + 1;
    father[nowp][0] = fa;
    for(int j = 1; j <= lg[depth[nowp]] + 1; j++) {
        father[nowp][j] = father[father[nowp][j - 1]][j - 1];
    }
    for(int i = 0; i < vec[nowp].size(); i++) {
        if(vec[nowp][i] != fa) {
            dfs(vec[nowp][i], nowp);
        }
    }
}
int LCA(int u, int v) {
    if(depth[u] < depth[v]) {
        swap(u, v);
    }
    while(depth[u] != depth[v]) {
        u = father[u][lg[depth[u] - depth[v]]];
    }
    if(u == v) {
        return u;
    }
    for(int j = lg[depth[u]]; j >= 0; j--) {
        if(father[u][j] != father[v][j]) {
            u = father[u][j];
            v = father[v][j];
        }
    }
    return father[u][0];
}
int main() {
    int u, v;
    int n, m, s;
    n = read(); m = read(); s = read();
    for(int i = 1; i <= n - 1; i++) {
        u = read();
        v = read();
        vec[u].push_back(v);
        vec[v].push_back(u);
    }
    for(int i = 2; i <= n; i++) {
        lg[i] = lg[i >> 1] + 1;
    }
    dfs(s, 0);
    while(m--) {
        u = read(); v = read();
        printf("%d\n", LCA(u, v));
    }
    return 0;
}
3.RMQ(咕咕)
4.tarjan(咕咕)