题目大意:
给出一棵有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;
}