【Luogu P3398】 仓鼠找sugar

题目大意:

一棵树,判断 \(a\) 节点到 \(b\) 节点的最短路径是否与 \(c\) 节点到 \(d\) 节点的最短路径相交。

正文:

容易得到,若两条路径相交,那么某条路径的公共祖先位于另一条的路径里。既然这样,那问题就简化为了判断某条路径的公共祖先是否位于另一条的路径里。

代码:

{
	q.push(root); d[root] = 1;
	while (!q.empty())
	{
		int x = q.front(); 
		q.pop();
		for (int i = head[x]; i; i = next[i])
		{
			int y = to[i];
			if (d[y]) continue;
			d[y] = d[x] + 1;
			f[y][0] = x;
			for (int j = 1; j <= num; j++)
				f[y][j] = f[f[y][j - 1]][j - 1];
			q.push(y);
		}
	} 
} 

int lca (int x, int y)
{
	if (d[x] > d[y])
	{
		int t = x;
		x = y;
		y = t;
	}
	for (int i = num; i >= 0; i--)
		if (d[f[y][i]] >= d[x])
			y = f[y][i];
	if (x == y) return x;
	for (int i = num; i >= 0; i--)
		if (f[x][i] != f[y][i])
		{
			x = f[x][i];
			y = f[y][i];
		}
	return f[x][0];
}

int dis(int a, int b)
{
	int c = lca(a, b);
	return abs(d[a] - d[c]) + abs(d[b] - d[c]);
}

int main()
{
	scanf ("%d%d", &n, &m); num = (int) (log2(n)) + 1;
	for (int i = 1; i < n; i++)
	{
		int x, y;
		scanf ("%d%d", &x, &y);
		add(x, y), add(y, x);
	}
	bfs (1);
	for (int i = 1; i <= m; i++)
	{
		int a, b, c, d;
		scanf ("%d%d%d%d", &a, &b, &c, &d);
		int x = lca(a, b), y = lca(c, d);
		if(dis(x, c) + dis(x, d) == dis(c, d) ||
		   dis(y, a) + dis(y, b) == dis(a, b))
			puts("Y");
		else puts("N");
	}
	return 0;
}
posted @ 2020-08-10 21:36  Jayun  阅读(79)  评论(0编辑  收藏  举报