#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int head[maxn],tot;
struct nn{int v,nxt;}g[maxn<<1];
void add_edge(int u,int v){g[++tot]={v,head[u]};head[u]=tot;}
int T,n,m,cnt,d[maxn],dep[maxn],pre[maxn][22];//pre倍增 ,d存度数
map<string,int>mp;
string a,b;
void init(int u,int fa)
{
dep[u]=dep[fa]+1;
pre[u][0]=fa;
for(int i=1;i<=20;i++){
if ((1<<i)<=dep[u])pre[u][i]=pre[pre[u][i-1]][i-1];
//往上跳
else pre[u][i]=0; //长度比自己深度还大时,不能跳,即前一个没有,用0表示
}
for(int i=head[u];i;i=g[i].nxt){
int v=g[i].v;
if(v!=fa) {init(v,u);}
}
}
int get_lca(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
//让u总为距离更远的那个
for(int i=20;i>=0;i--)
if(dep[u]-(1<<i)>=dep[v]) u=pre[u][i];
//最后uv跳到同一层
if(u==v) return u;
//若在同一层,值也相等,说明它就是公共祖先,直接返回
for(int i=20;i>=0;i--)//i==0时可以只跳一层,
if(pre[u][i]!=pre[v][i]) {u=pre[u][i];v=pre[v][i];}
//最后uv都跳到公共祖先的下一层,所以返回父节点
return pre[u][0];//即father[u]
}
int main() {
ios::sync_with_stdio(false);
cin>>T;
while (T--){
mp.clear();cnt=0;
cin>>n>>m;
for (int i=1;i<=n;i++)head[i]=d[i]=dep[i]=0;tot=0;
for (int i=1;i<n;i++){
cin>>a>>b;//a的父节点是b
if (mp[a]==0)mp[a]=++cnt;
if (mp[b]==0)mp[b]=++cnt;
//字母转数字 (入A为0,B为1,数字方便表示)
add_edge(mp[b],mp[a]);d[mp[a]]++;//所以a的入度++
}
int root;
for (int i=1;i<=n;i++)if (d[i]==0)root=i;
//找根节点
init(root,0);
while (m--){
cin>>a>>b;
int LCA=get_lca(mp[a],mp[b]);
if (LCA==mp[b])printf("%d\n",dep[mp[a]]-dep[mp[b]]);
//b是a的祖先
else printf("%d\n",dep[mp[a]]-dep[LCA]+1);
//a是b的祖先节点则 dep[mp[a]]-dep[LCA]=0,所以需要一次操作
//若互不是对方祖先,a变到b,a的深度-lca的深度(a到lca)+ 1(从lca到b)
}
}
return 0;
}
“相关推荐”对你有帮助么?
-
非常没帮助
-
没帮助
-
一般
-
有帮助
-
非常有帮助
提交