codeforcesLCA题_519E(div2)

文章介绍了在给定一棵有n个节点的树和m次询问的情况下,如何通过计算LCA并进行分类讨论来确定每次询问中距离相等的点的数量。方法包括深度相同、深度不同以及奇偶性分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接

题目大意:

给出一棵有n个节点的树,有m次询问,每次询问距离(a,b)相等的点有多少个。

思路:

我们可以通过

 

LCA来解答,同时也要分类讨论。

一.a,b的深度相同:

        1. a和b表示的数相同:

                直接输出n就可以了。

        2.a和b表示的数不同:

                让a和b跳到离(a,b)的LCA差一步的点,再输出n减去a的节点数和b的节点数。

二.a,b的深度不同:

        1.a和b的距离为奇数:

                不可能有答案,输出0。

         2.a和b的距离不为奇数

                使a的深度大于b的深度,找到a,b的中点,再找到距离中点1的点,输出a的节点数减去            b的节点数。

代码:

#include<bits/stdc++.h>
using namespace std;
inline int read() {
	int x = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-')f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
	return x * f;
}//快读
const int N = 1e5 + 110;
int fa[N], jump[N][21], d[N], siz[N];
//用来LCA
vector<int> v[N];
void dfs(int x) {
	d[x] = d[jump[x][0]] + 1;
	siz[x] = 1;
	for (int i = 1; i <= 20; i++)
		jump[x][i] = jump[jump[x][i - 1]][i - 1];
	for (int i = 0; i < (int)(v[x].size()); i++)
		if (v[x][i] != jump[x][0]) {
			jump[v[x][i]][0] = x;
			dfs(v[x][i]);
			siz[x] += siz[v[x][i]];
		}
}//初始化LCA
int lca(int x, int y) {
	if (d[x] < d[y]) swap(x, y);
	for (int i = 20; i >= 0; i--)
		if (d[jump[x][i]] >= d[y])
			x = jump[x][i];
	if (x == y)
		return x;
	for (int i = 20; i >= 0; i--)
		if (jump[x][i] != jump[y][i])
			x = jump[x][i], y = jump[y][i];
	return jump[x][0];
}
int up(int x, int step) {
	for (int i = 20; i >= 0; i--)
		if ((step >> i) & 1)
			x = jump[x][i];
	return x;

}//往上跳step步
signed main() {
	int n = read();
	for (int i = 1; i <= n; i++) fa[i] = i;
	for (int i = 1; i < n; i++) {
		int x = read(), y = read();
		v[x].push_back(y);
		v[y].push_back(x);
	}
	dfs(1);
	int m = read();
	for (int i = 1; i <= m; i++) {
		int x = read(), y = read();
		int c = lca(x, y);
		int s = d[x] + d[y] - 2 * d[c];
		if (d[x] == d[y])
			if (x == y)
				cout << n << endl;
			else {
				x = up(x, d[x] - d[c] - 1);
				y = up(y, d[y] - d[c] - 1);
				cout << n - siz[x] - siz[y] << endl;
			} else if (s & 1)
			cout << 0 << endl;
		else {
			if (d[x] < d[y])
				swap(x, y);
			int zhd = up(x, s / 2);
			int t = up(x, d[x] - d[zhd] - 1);
			cout << siz[zhd] - siz[t] << endl;
		}//四次分类讨论
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值