题意:给一棵n个点的树,m次询问,第i次询问有多少点到和
距离相等(所有边长均为1)。
题解:每次询问考虑路径上的中点,分中点是/不是LCA两种情况讨论一下即可。本以为这种要讨论的咋也得调一小会儿,结果居然1A......再加上懒得画图,所以贴个Codeforces的链接捡懒。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+4;
int n,q;
struct Edge {
int v,nxt;
}e[N<<1];
int head[N],etot;
int f[18][N];
int dep[N],siz[N];
inline void adde(int u,int v) {
e[++etot].nxt=head[u],e[etot].v=v,head[u]=etot;
}
inline int read() {
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
void dfs(int p,int fa) {
siz[p]=1;
dep[p]=dep[fa]+1;
f[0][p]=fa;
for (int i=1;i<18;++i)
f[i][p]=f[i-1][f[i-1][p]];
for (int i=head[p];~i;i=e[i].nxt) {
int v=e[i].v;
if (v^fa) {
dfs(v,p);
siz[p]+=siz[v];
}
}
}
inline int lca(int a,int b) {
if (dep[a]<dep[b]) a^=b^=a^=b;
int d=dep[a]-dep[b];
for (int i=17;~i;--i)
if (d&(1<<i)) a=f[i][a];
if (a==b) return a;
for (int i=17;~i;--i)
if (f[i][a]^f[i][b]) {
a=f[i][a];
b=f[i][b];
}
return f[0][a];
}
inline int up(int x,int len) {
for (int i=17;~i;--i)
if (len&(1<<i)) x=f[i][x];
return x;
}
int main() {
memset(head,-1,sizeof(head));
n=read();
for (register int i=1;i<n;++i) {
int u=read(),v=read();
adde(u,v);
adde(v,u);
}
dfs(1,0);
q=read();
while (q--) {
int a=read(),b=read();
int fa=lca(a,b);
int d=dep[a]+dep[b]-(dep[fa]<<1);;
if (d&1) {
puts("0");
continue;
}
if (dep[a]^dep[b]) {
if (dep[a]<dep[b]) a^=b^=a^=b;
int t=up(a,(d>>1)-1);
printf("%d\n",siz[f[0][t]]-siz[t]);
} else {
int l=up(a,(d>>1)-1);
int r=up(b,(d>>1)-1);
printf("%d\n",siz[1]-siz[l]-siz[r]);
}
}
return 0;
}