|
|
#include <bits/stdc++.h>
|
|
|
using namespace std;
|
|
|
|
|
|
typedef pair<int, int> PII;
|
|
|
const int N = 500010, M = N << 1;
|
|
|
|
|
|
// 链式前向星
|
|
|
int e[M], h[N], idx, w[M], ne[M];
|
|
|
void add(int a, int b, int c = 0) {
|
|
|
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
|
|
|
}
|
|
|
|
|
|
vector<PII> query[N]; // query[u]: first:询问的另一个顶点; second:询问的编号
|
|
|
|
|
|
int n, m, s;
|
|
|
int p[N]; // 并查集数组
|
|
|
bool st[N]; // tarjan算法求lca用到的是否完成访问的标识
|
|
|
int lca[N]; // 结果数组
|
|
|
|
|
|
int find(int x) {
|
|
|
if (p[x] != x) p[x] = find(p[x]); // 路径压缩
|
|
|
return p[x];
|
|
|
}
|
|
|
|
|
|
void tarjan(int u) {
|
|
|
// ① 标识u已访问
|
|
|
st[u] = true;
|
|
|
// ② 枚举u的临边,tarjan没有访问过的点
|
|
|
for (int i = h[u]; ~i; i = ne[i]) {
|
|
|
int j = e[i];
|
|
|
if (!st[j]) {
|
|
|
tarjan(j);
|
|
|
// ③ 完成访问后,j点加入u家族
|
|
|
p[j] = u;
|
|
|
}
|
|
|
}
|
|
|
// ④ 每个已完成访问的点,记录结果
|
|
|
for (auto q : query[u]) {
|
|
|
int v = q.first, id = q.second;
|
|
|
if (st[v]) lca[id] = find(v);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int main() {
|
|
|
memset(h, -1, sizeof h);
|
|
|
scanf("%d %d %d", &n, &m, &s);
|
|
|
|
|
|
int a, b;
|
|
|
for (int i = 1; i < n; i++) {
|
|
|
scanf("%d %d", &a, &b);
|
|
|
add(a, b), add(b, a);
|
|
|
}
|
|
|
|
|
|
for (int i = 1; i <= m; i++) {
|
|
|
scanf("%d %d", &a, &b);
|
|
|
query[a].push_back({b, i});
|
|
|
query[b].push_back({a, i});
|
|
|
}
|
|
|
|
|
|
// 初始化并查集
|
|
|
for (int i = 1; i <= n; i++) p[i] = i;
|
|
|
tarjan(s);
|
|
|
|
|
|
// 输出答案
|
|
|
for (int i = 1; i <= m; i++) printf("%d\n", lca[i]);
|
|
|
return 0;
|
|
|
} |