#include<cstdio>
#include<string.h>
#include<vector>
#define N 10050
using namespace std;
int T,n,a,b,deep[N],g[N][21];
bool vis[N];
vector<int> p[N<<1];
void dfs(int x){
for(int i = 0;i < p[x].size();i ++){
if(!deep[p[x][i]]){
deep[p[x][i]] = deep[x]+1;//兒子比爸爸深1
g[p[x][i]][0] = x;//從兒子向上跳2^0 步是爸爸
dfs(p[x][i]);
}
}
}
int lca(int a,int b){
if(deep[a] < deep[b]) swap(a,b);
int t = deep[a] - deep[b];
for(int i = 0;i <= 20;i ++) //取t的每一個2的n次,跳到相同
if((1<<i)&t) a = g[a][i];
if(a == b) return a;
for(int i = 20;i >= 0;i --)
if(g[a][i] != g[b][i]){
a = g[a][i];
b = g[b][i];
}
return g[a][0];
}
int main(){
scanf("%d",&T);
while(T --){
memset(g,0,sizeof g);
memset(p,0,sizeof p);
memset(vis,false,sizeof vis);
memset(deep,0,sizeof deep);
scanf("%d",&n);
for(int i=1;i<n;i ++){
scanf("%d%d",&a,&b);
p[a].push_back(b);
vis[b] = true;
}
scanf("%d%d",&a,&b);
for(int i=1;i<=n;i ++){
if(!vis[i]){//保證從根節點開始
dfs(i);
break;
}
}
for(int j = 1;j <= 20;j ++)
for(int i = 1;i <= n;i ++)
g[i][j] = g[g[i][j-1]][j-1];
printf("%d\n",lca(a,b));
}
return 0;
}
步驟分解:
- 用好用的vector記錄每個父親有哪些兒子,順便找到根節點——不是任何點的兒子;
- 從根節點開始dfs(i),每次都算出 i 的所有兒子的深度,順便寫上兒子向上跳一步是爸爸,然後dfs兒子。
- 遞推出g數組。
- 求lca。假設a深度比b大,根據深度差,跳跳跳,直到一樣深。再從大到小跳,當跳那麼多步不相同,就意味着還沒到 lca,可以一起向上跳。最後得到的a、b,是最後一次a、b不一樣,再往上跳1步就是lca了。