1330 -- Nearest Common Ancestors
题目大意:有一棵n个点的树,求两个点的最近公共组先
思路:(tarjan)进行后序dfs遍历,优先遍历更深的节点,在回溯时维护其父结点信息,在访问到一点后,再访问另一点时,已访问过的点的当前的父结点即两个点的LCA,求多个点对的LCA只需每个要查询的点对之间建一条边即可,多个点的LCA为dfs序最小和最大的点的LCA
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int N = 1e4 + 5;
vector<int>g[N], p[N];
int vis[N], fa[N], flag[N], ans, n;
void init()
{
for (int i = 1; i <= n; i++)
{
fa[i] = i;
g[i].clear();
p[i].clear();
}
memset(vis, 0, sizeof vis);
memset(flag, 0, sizeof flag);
}
int find(int x)
{
return fa[x] == x ? x : find(fa[x]);
}
void tarjan(int x)
{
for (int i = 0; i < g[x].size(); i++)
{
int xx = g[x][i];
tarjan(xx);
fa[xx] = x;//遍历到最底层的节点后,在回溯时保存父结点信息
}
vis[x] = 1;
for (int i = 0; i < p[x].size(); i++)
{
int xx = p[x][i];
if (vis[xx])//如果其中一个点已经被访问过,那么这两个点的LCA就是访问过的点的父结点
{
ans = find(xx);
return;
}
}
}
int main()
{
int t;
cin >> t;
while (t--)
{
scanf_s("%d", &n);
init();
for (int i = 1; i < n; i++)
{
int x, y;
scanf_s("%d %d", &x, &y);
g[x].push_back(y);
flag[y]++;//统计点的入度
}
int u, v;
scanf_s("%d %d", &u, &v);
p[u].push_back(v);
p[v].push_back(u);
for (int i = 1; i <= n; i++)
{
if (!flag[i])
tarjan(i);
}
printf("%d\n", ans);
}
return 0;
}