时间限制: 1 s
空间限制: 128000 KB
题目等级 : 黄金 Gold
题目描述 Description
顾名思义.
给一棵有根树,以及一些询问,每次询问树上的2 个节点A、B,求它
们的最近公共祖先.
输入描述 Input Description
第一行一个整数N.接下来N 个数,第i 个数Fi 表示i 的父亲是Fi. 若Fi = 0,则i 为树根.接下来一个整数M.接下来M 行,每行2 个整数A、B,询问节点(A xor LastAns)、(B xor LastAns)的最近公共祖先. 其中LastAns 为上一个询问的答案,一开始LastAns = 0.
输出描述 Output Description
对每一个询问输出相应的答案.
样例输入 Sample Input
10
0 1 2 3 2 4 2 5 4 9
10
3 9
2 7
7 8
1 1
0 6
6 11
6 3
10 7
2 15
7 7
样例输出 Sample Output
3
1
4
5
2
4
2
5
2
5
数据范围及提示 Data Size & Hint
30% n,m≤1000
100% n,m≤100,000
好久不打LCA
#include<cstdio>
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;
#define N 100005
#define M 21
struct LCA{
vector<int> g[N];
int root,ans,n,m;
int d[N],f[N][M];
void dfs(int x,int dp){
d[x]=dp;
for(int i=0;i<g[x].size();i++){
if(!d[g[x][i]]){
dfs(g[x][i],dp+1);
f[g[x][i]][0]=x;
}
}
}
void work(){
for(int i=1;i<=20;i++)
for(int j=1;j<=n;j++)
f[j][i]=f[f[j][i-1]][i-1];
}
int lca(int u,int v){
if(d[u]<d[v]) swap(u,v);
int l=d[u]-d[v];
if(l)
for(int i=0;i<=20;i++)
if(l&(1<<i)) u=f[u][i];
if(u==v) return u;
for(int i=20;i>=0;i--){
if(f[u][i]!=f[v][i])
u=f[u][i],v=f[v][i];
}
return f[u][0];
}
void init(){
scanf("%d",&n);int x,y;
for(int i=1;i<=n;i++){
scanf("%d",&x);
if(x) g[x].push_back(i);
else root=i;
}
dfs(root,0);work();ans=0;
scanf("%d",&m);
while(m--){
scanf("%d%d",&x,&y);
ans=lca(x^ans,y^ans);
printf("%d\n",ans);
}
}
}s;
int main(){
s.init();
return 0;
}