L2-4 缘之空

题目描述:
小悠和小穹是一对恋人,有天他们讨论起彼此的家庭,惊讶地发现他们很有可能是远房亲戚。
为了避免发生一些遗传学上比较糟糕的事情,他们决定求助于你,你能帮帮他们么?
家谱中有 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;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值