********************************************
这题是公共祖先模板题。
我们用倍增方法去写。
首先我们找到根节点,然后从当前根节点往下dfs
在dfs的过程中我们遍历的节点初始上一步的节点f[u][0] = father
然后再初始化后几步的节点。
for(int i = 1;i<=20;++i){ //往上跳2^i步的节点
f[u][i] = f[f[u][i-1]][i-1];
}
这样我们倍增出了关于当前节点的倍增父节点。
然后我们遍历子节点,更新其深度,方便后面找公共祖先时平衡两节点的深度在同一个位置上。
for(int i:arr[u]){
if(i==father)continue;
dep[i] = dep[u] + 1; //往下更新下节点的深度
dfs(i,u);
}
到后面的查询操作:
我们一开始先平衡两节点的深度到达同一个位置。
然后开始往上慢慢找第一个深度最大的不同节点, 就能找到公共最近节点了。
ac code:
#include<bits/stdc++.h>
using namespace std;
const int N = 4e4+5;
vector<int>arr[N];
int root;
int dep[N]; //节点深度
int f[N][26]; //往上跳2^i步的父节点
void dfs(int u,int father){ //更新节点深度和跳一步的父节点
if(father==-1)f[u][0]=u; //如果当前节点是根
else f[u][0] = father; //不是根就指向上一级节点
for(int i = 1;i<=20;++i){ //往上跳2^i步的父节点
f[u][i] = f[f[u][i-1]][i-1];
}
for(int i:arr[u]){
if(i==father)continue;
dep[i] = dep[u] + 1; //往下更新下节点的深度
dfs(i,u);
}
}
int LCA(int a,int b){
int op = 1; //没交换
if(dep[a]<dep[b]){ //将深度大的变a
swap(a,b);
op = 2; //交换状态
}
while(dep[a]>dep[b]){
for(int i = 20;i>=0;--i){ //贪心跳最大
if(dep[f[a][i]]>=dep[b]){ //如果跳了深度大于等于b就跳
a = f[a][i];
break;
}
}
}
if(a==b){ //如果a往上跳等于b,说明其中一方是另一方的公共祖先
if(op==1)return 2; //没交换时,y是x的公共祖先
else return 1; //x是y的公共祖先
}
return 0;
}
void solve(){
int n;cin>>n;
for(int i = 1;i<=n;++i){
int a,b;cin>>a>>b;
// cout<<i<<' '<<a<<' '<<b<<endl;
if(a==-1){root = b;continue;}
if(b==-1){root = a;continue;}
arr[a].push_back(b);
arr[b].push_back(a);
}
dfs(root,-1);
int k;cin>>k;
while(k--){
int a,b;cin>>a>>b;
int res = LCA(a,b);
cout<<res<<endl;
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
solve();
}