传送门
Description
在大学里,小A和小B是一对非常要好的朋友,他们经常一起参加比赛。现在,这个大学里有n个教室,这n个教室用n-1个走廊相互连接,因此学生可以从一个教室经过走廊走到任何其他的教室。
每天,小A和小B都要讨论一些问题。每次下课以后(小A和小B在不同的地方上课),小A和小B就相约去同一个教室讨论问题。小A和小B希望讨论的教室离他们现在各自所在的教室距离相等。两个教室之间的距离指的是他们的最短距离。
由于小A和小B每天都要讨论问题,所以他们希望你能帮助他们计算出在接下来的m天里,离他们各自所在的位置距离相等的教室有多少个。
Input
输入第一行是一个正整数n,表示教室的数量。1<=n<=10^ 5。接下来n-1行,每行两个数a和b,表示a和b之间有一条走廊相通。接下来是一个正整数m,表示天数,1<=m<=10^ 5。接下来m行,每行两个数x和y(1<=x,y<=n), 表示每天小A和小B各自所在的教室编号,x有可能等于y。
Output
输出m行,对于每天,输出离小A和小B距离相等的教室的数量。
思路:第一反应是这道题能做。我们知道给的是一棵无向边树,我们求点到 s和e距离相等点的数量。 我可以很容易得到一个结论,如果两个点之间的距离是奇数,那么很明显答案为0。我们就要讨论距离为偶数的情况,两个点之间的链上面必有一个中点到s和e的距离相等,这个点就是一个关键点(我们该关键点为x)。当LCA(s,e)= x,答案就等于 n 减去s 和 e 两个分支上总节点数。当LCA(s,e)!= x,则说明 LCA(s,e)是 x 的祖先,x 是 s 或 e 的祖先,那么答案等于以 x 为根的树的节点数减去x 的儿子(该儿子应该是 s 或 e 的祖先,也可能是 s 或者 e 本身)为根的树的节点数。
坑点:当s==e时,答案应该为n。
附上代码:
///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<bitset>
#include<set>
#include<stack>
#include<map>
#include<list>
#include<new>
#include<vector>
#define MT(a,b) memset(a,b,sizeof(a));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const double E=2.718281828459;
const ll mod=1e12;
const ll INF=0x3f3f3f3f3f3f;
int n,q;
struct node
{
int e;
int p;
} load[200005];
int head[100005],sign;
void add_edge(int s,int e)
{
load[++sign]=node{e,head[s]};
head[s]=sign;
}
int grand[100005][20],N;
int depth[100005];
int son[100005];
void init()
{
N=log2(n);
memset(grand,0,sizeof(grand));
for(int i=1; i<=n; i++)
{
head[i]=-1;
depth[i]=0;
son[i]=1;
}
depth[0]=-1;
}
void dfs(int s,int pre)
{
for(int i=1; i<=N; i++)
grand[s][i]=grand[grand[s][i-1]][i-1];
for(int i=head[s]; i!=-1; i=load[i].p)
{
int e=load[i].e;
if(e!=pre)
{
depth[e]=depth[s]+1;
grand[e][0]=s;
dfs(e,s);
son[s]+=son[e];
}
}
}
int get_lca(int a,int b)
{
if(depth[a]>depth[b])
swap(a,b);
for(int i=N; i>=0; i--)
if(depth[b]>=depth[a]&&depth[grand[b][i]]>=depth[a])
b=grand[b][i];
for(int i=N; i>=0; i--)
{
if(grand[a][i]!=grand[b][i])
{
a=grand[a][i];
b=grand[b][i];
}
}
return a==b?a:grand[b][0];
}
int jump(int now,int d)
{
for(int i=N; i>=0; i--)
{
if(depth[now]>=d&&depth[grand[now][i]]>=d)
now=grand[now][i];
}
return now;
}
int main()
{
int s,e;
scanf("%d",&n);
init();
for(int i=1; i<n; i++)
{
scanf("%d %d",&s,&e);
add_edge(s,e);
add_edge(e,s);
}
dfs(1,-1);
scanf("%d",&q);
while(q--)
{
scanf("%d %d",&s,&e);
if(s==e)
{
printf("%d\n",n);
continue;
}
int x=get_lca(s,e);
int len=depth[s]+depth[e]-2*depth[x];
if(len&1)
printf("0\n");
else
{
int adv=len/2;
int a=depth[s]-depth[x];
int b=depth[e]-depth[x];
if(a==b)
{
int c=jump(s,depth[x]+1);
int d=jump(e,depth[x]+1);
printf("%d\n",n-son[c]-son[d]);
}
else
{
if(a>b)
x=jump(s,depth[s]-adv+1);
else
x=jump(e,depth[e]-adv+1);
printf("%d\n",son[grand[x][0]]-son[x]);
}
}
}
}