#include<iostream>
using namespace std;
int tree[10001][100],in[10001],p[10001];
int cas,s,t;
int n,Q1,Q2;
bool v[10001];
void Make_Set(int t)
{
p[t]=t;
}
int Find_Set(int t)
{
if(t!=p[t])
{
p[t]=Find_Set(p[t]);
}
return p[t];
}
void Union(int u,int v)
{
p[v]=u;
}
int LCA(int u)
{
Make_Set(u);
int i;
for(i=1;i<=tree[u][0];i++)
{
LCA(tree[u][i]);
Union(u,tree[u][i]);
}
v[u]=1;
if(u==Q1&&v[Q2])
{
printf("%d\n",p[Find_Set(Q2)]);
}
else if(u==Q2&&v[Q1])
{
printf("%d\n",p[Find_Set(Q1)]);
}
return 0;
}
int main()
{
scanf("%d",&cas);
while(cas--)
{
int i;
memset(tree,0,sizeof(tree));
memset(in,0,sizeof(in));
memset(v,0,sizeof(v));
scanf("%d",&n);
for(i=1;i<n;i++)
{
scanf("%d%d",&s,&t);
tree[s][++tree[s][0]]=t;
in[t]++;
}
scanf("%d%d",&Q1,&Q2);
for(i=1;i<=n;i++)
{
if(in[i]==0)
break;
}
LCA(i);
}
system("pause");
return 0;
}
Tarjan算法基于深度优先搜索的框架,对于新搜索到的一个结点,首先创建由这个结点构成的集合,再对当前结点的每一个子树进行搜索,每搜索完一棵子树,则可确定子树内的LCA询问都已解决。其他的LCA询问的结果必然在这个子树之外,这时把子树所形成的集合与当前结点的集合合并,并将当前结点设为这个集合的祖先。之后继续搜索下一棵子树,直到当前结点的所有子树搜索完。这时把当前结点也设为已被检查过的,同时可以处理有关当前结点的LCA询问,如果有一个从当前结点到结点v的询问,且v已被检查过,则由于进行的是深度优先搜索,当前结点与v的最近公共祖先一定还没有被检查,而这个最近公共祖先的包涵v的子树一定已经搜索过了,那么这个最近公共祖先一定是v所在集合的祖先。 贴一个地址吧:
http://yinyifan.com/blog/2008/11/lowest_common_ancester_tarjan_alogrithm