一. 题目
二. 思路
倍增法:
f[i, j]:从节点i开始,向上走2^j次方步所能走到的节点。0<=j<=log(n)。
depth[i]:表示节点i的深度。
首先,将两个点跳到同一层。
然后,让两个点同时网上跳,一直到他们最近公共祖先的下一层。
预处理O(nlogn)、查询logn。
三. 代码
import java.io.*;
import java.util.*;
public class Main
{
static final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static final BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
static String[] ts;
static final int N = (int) 4e4 + 10, M = 2 * N, K = 20, INF = Integer.MAX_VALUE;//0~15
static int[] h = new int[N], e = new int[M], ne = new int[M];
static int n, m, idx;
static int[] depth = new int[N];
static int[][] f = new int[N][K];
static void add(int a, int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
static void dfs(int u, int fa)
{
depth[u] = depth[fa] + 1;
f[u][0] = fa;
for (int i = 1; i <= 15; ++i)//更新
f[u][i] = f[f[u][i - 1]][i - 1];
for (int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if (j == fa) continue;
dfs(j, u);
}
}
static int LCA(int a, int b)
{
int t = a;
if (depth[a] < depth[b])//a的深度大
{
a = b;
b = t;
}
for (int i = 15; i >= 0; i--)
if (depth[f[a][i]] >= depth[b])//若a跳完深度>=b则可以跳
a = f[a][i];
if (a == b) return a;
for (int i = 15; i >= 0; --i)//同一高度
if (f[a][i] != f[b][i])//a, b跳完不相等
{
a = f[a][i];
b = f[b][i];
}
return f[a][0];
}
public static void main(String[] args) throws Exception
{
Arrays.fill(h, -1);
ts = br.readLine().split(" ");
n = Integer.parseInt(ts[0]);
int root = 0;
for (int i = 0; i < n; ++i)
{
int a, b;
ts = br.readLine().split(" ");
a = Integer.parseInt(ts[0]);
b = Integer.parseInt(ts[1]);
if (b == -1) root = a;
else
{
add(a, b);
add(b, a);
}
}
//depth[0] = 0;
dfs(root, 0);
ts = br.readLine().split(" ");
m = Integer.parseInt(ts[0]);
for (int i = 0; i < m; ++i)
{
int a, b;
ts = br.readLine().split(" ");
a = Integer.parseInt(ts[0]);
b = Integer.parseInt(ts[1]);
int t = LCA(a, b);
if (t == a) bw.write("1");
else if (t == b) bw.write("2");
else bw.write("0");
bw.newLine();
}
bw.close();
}
}