DTOJ3373 约会

题目

题目描述

Vincent和他的大学GF不在同一个院系中,但他们每天都要约在校园中的同一个地方见面
THU的地图可以抽象为一个$n$个结点的一棵树,即有$n$个地点,$n-1$条无向边,每条边的长度为$1$,任意两个地点之间是连通的树还能不连通!?
由于每天的课程不同,他们每天所在的位置也不同,第$i$天,Vincent在地点$x_i$,他的GF在地点$y_i$
由于不能让某一方走的路程过多,所以他们约会的地点有个要求,必须与两人的位置之间的距离相等,距离指在树上的最短路径
请你帮Vincent算算每天他们有多少种可选的约会地点

输入格式

第一行一个整数$n$
接下来$n-1$行,每行两个整数$u$和$v$,表示树上有一条$u$和$v$之间的边
接下来一行一个整数$m$,表示他们有$m$天要约会见面
接下来$m$行,每行两个整数$x_i,y_i$,表示第$i$天,他们各自的位置

输出格式

对于每一天,输出一行一个整数,表示第$i$天可行的约会地点有多少个

样例

样例输入

1
2
3
4
5
6
4
1 2
1 3
2 4
1
2 3

样例输出

1
1

数据范围与提示

样例解释

约会地点$1$是可行的

数据范围及约定

对于$25 \%$的数据,$n,m \leqslant 100$
对于$50 \%$的数据,$n,m \leqslant 10^3$
另外存在$20 \%$的数据,树是一条链
另外存在$15 \%$的数据,树是随机生成的
对于$100 \%$的数据,$n,m \leqslant 10^5$

题解

首先,以编号为$1$的点为根
对于一组询问$x,y$,如果$x$的深度小于$y$,那就交换他们的顺序
接着,求出它们的LCA,就可以求出链的长度
如果链的长度是偶数,那就没有中点,答案是$0$
如果链的长度是奇数,就求出链的中点
如果中点是它们的LCA,那么深度比LCA小的节点和不包含$x$和$y$的LCA的子树是可行的约会地点
若中点不是LCA,那么深度小于中点的点都不是可行的约会地点,深度大于中点的节点用类似于上面的求法求出来就可以了
附上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include<iostream>
using namespace std;
int n,m,tot,head[100010],nxt[200010],to[200010],dep[100010],Fa[100010][25],size[100010];
void add(int a,int b)
{
nxt[++tot]=head[a],head[a]=tot,to[tot]=b;
}
void dfs(int x,int fa)
{
dep[x]=dep[fa]+1,size[x]=1,Fa[x][0]=fa;
for(int i=1;i<=20;i++) Fa[x][i]=Fa[Fa[x][i-1]][i-1];
for(int i=head[x];i;i=nxt[i]) if(to[i]^fa) dfs(to[i],x),size[x]+=size[to[i]];
}
int lca(int x,int y)
{
for(int i=20;~i;i--) if(dep[Fa[x][i]]>=dep[y]) x=Fa[x][i];
for(int i=20;~i;i--) if(Fa[x][i]^Fa[y][i]) x=Fa[x][i],y=Fa[y][i];
if(x^y) return Fa[x][0];
else return y;
}
int find(int x,int y)
{
for(int i=20;~i;i--) if(y>>i&1) x=Fa[x][i];
return x;
}
int main()
{
cin>>n;
for(int i=1,x,y;i<n;i++) cin>>x>>y,add(x,y),add(y,x);
dfs(1,0),cin>>m;
for(int i=1,x,y,len,LCA;i<=m;i++){
cin>>x>>y;
if(dep[x]<dep[y]) swap(x,y);
LCA=lca(x,y),len=dep[x]+dep[y]-2*dep[LCA];
if(len&1) cout<<0;
else{
len>>=1;
int mid=find(x,len);
if(mid==x) cout<<n;
else if(mid==LCA) cout<<size[1]-size[find(x,len-1)]-size[find(y,len-1)];
else cout<<size[mid]-size[find(x,len-1)];
}
cout<<endl;
}
}