题目大意
给一个有根树,问你两个点的最近公共祖先
分析
虽然题目只查询一次,但用这道题来学习一下LCA的tarjan写法
代码
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#include<stack>
#include<vector>
using namespace std;
const int MAXN=21005;
int n;
int in[MAXN];
int vis[MAXN];
int fa[MAXN];
int Rank[MAXN];
vector<int> node[MAXN],que[MAXN];
int anse[MAXN];
void Init()
{
for(int i=1;i<=n;i++)
{
node[i].clear();
que[i].clear();
fa[i]=i;
Rank[i]=1;
}
memset(in,0,sizeof(in));
memset(vis,0,sizeof(vis));
memset(anse,0,sizeof(anse));
}
int Find(int a)
{
return fa[a]!=a ? fa[a]=Find(fa[a]) : a;
}
void Union(int a,int b)
{
int ta=Find(a);
int tb=Find(b);
if(ta==tb)return ;
if(Rank[ta]>Rank[tb])
{
fa[tb]=ta;
Rank[ta]+=Rank[tb];
}
else
{
fa[ta]=tb;
Rank[tb]+=Rank[ta];
}
}
void LCA(int root)
{
int i,sz;
anse[root]=root;
sz=node[root].size();
for(int i=0;i<sz;i++)
{
LCA(node[root][i]);
Union(root,node[root][i]);
anse[Find(node[root][i])]=root;
}
vis[root]=1;
sz=que[root].size();
for(int i=0;i<sz;i++)
{
if(vis[que[root][i]])
{
printf("%d\n",anse[Find(que[root][i])]);
return ;
}
}
return ;
}
int main()
{
int T;
int u,v;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
Init();
for(int i=1;i<=n-1;i++)
{
scanf("%d%d",&u,&v);
if(u!=v)
{
node[u].push_back(v);
in[v]++;
}
}
scanf("%d%d",&u,&v);
que[u].push_back(v);
que[v].push_back(u);
int root;
for(int i=1;i<=n;i++)if(in[i]==0){root=i;break;}
LCA(root);
}
return 0;
}