67 lines
1.6 KiB
C++
67 lines
1.6 KiB
C++
#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;
|
||
} |