Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 7458 | Accepted: 3889 |
Description

In the figure, each node is labeled with an integer from {1, 2,...,16}. Node 8 is the root of the tree. Node x is an ancestor of node y if node x is in the path between the root and node y. For example, node 4 is an ancestor of node 16. Node 10 is also an ancestor of node 16. As a matter of fact, nodes 8, 4, 10, and 16 are the ancestors of node 16. Remember that a node is an ancestor of itself. Nodes 8, 4, 6, and 7 are the ancestors of node 7. A node x is called a common ancestor of two different nodes y and z if node x is an ancestor of node y and an ancestor of node z. Thus, nodes 8 and 4 are the common ancestors of nodes 16 and 7. A node x is called the nearest common ancestor of nodes y and z if x is a common ancestor of y and z and nearest to y and z among their common ancestors. Hence, the nearest common ancestor of nodes 16 and 7 is node 4. Node 4 is nearer to nodes 16 and 7 than node 8 is.
For other examples, the nearest common ancestor of nodes 2 and 3 is node 10, the nearest common ancestor of nodes 6 and 13 is node 8, and the nearest common ancestor of nodes 4 and 12 is node 4. In the last example, if y is an ancestor of z, then the nearest common ancestor of y and z is y.
Write a program that finds the nearest common ancestor of two distinct nodes in a tree.
Input
Output
Sample Input
2 16 1 14 8 5 10 16 5 9 4 6 8 4 4 10 1 13 6 15 10 11 6 7 10 2 16 3 8 1 16 12 16 7 5 2 3 3 4 3 1 1 5 3 5
Sample Output
4 3
Source
#include<stdio.h>
#include<vector>
using namespace std;
const int MAX=10001;
int f[MAX];
int r[MAX];
int indegree[MAX];//保存每个节点的入度
int visit[MAX];
vector<int> tree[MAX],Qes[MAX];
int ancestor[MAX];
void init(int n)
{
for(int i=1;i<=n;i++)
{
r[i]=1;//类似于rank数组
f[i]=i;//用于并查集记录父亲节点
indegree[i]=0;//节点的层号
visit[i]=0;//是否被访问
ancestor[i]=0;//祖先
tree[i].clear();//清空
Qes[i].clear();
}
}
int find(int n)
{ //查找函数,并压缩路径
if(f[n]==n) return n;
else f[n]=find(f[n]);
return f[n];
}
int Union(int x,int y)
{ //合并函数,如果属于同一分支则返回0,成功合并返回1
int a=find(x);
int b=find(y);
if(a==b) return 0;
//相等的话,x向y合并
else if(r[a]<=r[b])
{
f[a]=b;
r[b]+=r[a];
}
else
{
f[b]=a;
r[a]+=r[b];
}
return 1;
}
void LCA(int u)
{
ancestor[u]=u;
int size=tree[u].size();
for(int i=0;i<size;i++)
{
LCA(tree[u][i]);
Union(u,tree[u][i]);
ancestor[find(u)]=u;
}
visit[u]=1;
size=Qes[u].size();
for(int i=0;i<size;i++)
{ //如果已经访问了问题节点,就可以返回结果了.
if(visit[Qes[u][i]]==1)
{
printf("%d/n",ancestor[find(Qes[u][i])]);
return;
}
}
}
int main()
{
int T;
int n;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
init(n);
int s,t;
for(int i=1;i<n;i++)
{
scanf("%d%d",&s,&t);
tree[s].push_back(t);
indegree[t]++;
}
scanf("%d%d",&s,&t);//这里可以输入多组询问
Qes[s].push_back(t);//相当于询问两次
Qes[t].push_back(s);
for(int i=1;i<=n;i++)
{ //寻找根节点
if(indegree[i]==0)
{
LCA(i);
break;
}
}
}
return 0;
}