题目描述:
小悠和小穹是一对恋人,有天他们讨论起彼此的家庭,惊讶地发现他们很有可能是远房亲戚。
为了避免发生一些遗传学上比较糟糕的事情,他们决定求助于你,你能帮帮他们么?
家谱中有 n 个人,编号为 1 到 n, 他们的血缘关系形成了一棵有根树。
定义两个人之间的亲缘等级为家谱树上两个人的距离,直系血亲(即一个人是另一个人的祖先)和亲缘等级小于等于4的旁系血亲不能结婚。
小悠和小穹想知道,对于给定的两个人,他们能否结婚。
链接:
https://ac.nowcoder.com/acm/problem/205711
思路:
找到入度为0的点,作为根节点,其他的就是lca模板了
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N = 1e6 + 10;
int e[N], ne[N], w[N], h[N], idx = 0;
int fa[N][20], depth[N];
queue<int>q;
void add(int a, int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
void dfs(int root)
{
q.push(root);
depth[root] = 1;
depth[0] = 0;
while (!q.empty())
{
int t = q.front();
q.pop();
for (int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
if (depth[j] > depth[t] + 1)
{
depth[j] = depth[t] + 1;
fa[j][0] = t;
q.push(j);
for (int k = 1; k < 20; k++)
{
fa[j][k] = fa[fa[j][k - 1]][k - 1];
}
}
}
}
}
int lca(int a, int b)
{
if (depth[a] < depth[b])
{
swap(a, b);
}
for (int k = 19; k >= 0; k--)
{
if (depth[fa[a][k]] >= depth[b])
{
a = fa[a][k];
}
}
if (a == b)
{
return a;
}
for (int k = 19; k >= 0; k--)
{
if (fa[a][k] != fa[b][k])
{
a = fa[a][k];
b = fa[b][k];
}
}
return fa[a][0];
}
int din[N];
int main()
{
memset(h, -1, sizeof h);
memset(depth, 0x3f, sizeof depth);
int n, q;
cin >> n >> q;
for (int i = 0; i < n - 1; i++)
{
int a, b;
cin >> a >> b;
add(a, b);
add(b, a);
din[b]++;
}
int root = 0;
for (int i = 1; i <= n; i++)
{
if (!din[i])
{
root = i;
}
}
dfs(root);
for (int i = 0; i < q; i++)
{
if (i != 0)
{
cout << endl;
}
int a, b;
cin >> a >> b;
int t = lca(a, b);
int dis = depth[a] + depth[b] - depth[t] * 2;
if (a == t || b == t)
{
cout << "NO" << endl;
}
else if (dis <= 4)
{
cout << "NO" << endl;
}
else
{
cout << "YES" << endl;
}
cout << dis;
}
}