题目链接:Closest Common Ancestors
题目大意:给你一棵树,给你多个点对,问:最近公共祖先相同的点对的个数,根据祖先按从小到大输出,并输出个数。
思路:
LCA的模板题。
代码:
#include<stdio.h>
#include<string.h>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e3+9;
int firs[maxn],vis[maxn],fath[maxn],h[maxn],inq[maxn];
//fath并查集记录祖先,h记录每个点的入度,用来求根节点,inq 记录每个祖先的点对的个数。
int N,M;
vector<int>g[maxn];
struct node
{
int v,nex;
} edge[maxn];
void build_edge(int u,int v)//建有向边
{
edge[N]=(node)
{
v,firs[u]
};
firs[u]=N++;
}
void init(int n)//初始化
{
N=M=0;
for(int i=1; i<=n; i++)
{
inq[i]=0;
g[i].clear();
firs[i]=-1;
vis[i]=0;
fath[i]=i;
h[i]=0;
}
}
int find(int x)//查找祖先节点
{
if(fath[x]==x)
return x;
return fath[x]=find(fath[x]);
}
void Trajan(int u)
{
for(int i=firs[u]; i!=-1; i=edge[i].nex)//深搜点
{
int v=edge[i].v;
Trajan(v);
fath[v]=u;//更新并查集
vis[v]=1;//记录访问过
}
for(int i=0; i<g[u].size(); i++)//访问所有与u有关的询问
{
int v=g[u][i];
if(vis[v])
{
int f1=find(v);//查找点对(u,v),的最近公共祖先
inq[f1]++;//记录祖先的点对个数。
}
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
init(n);
for(int i=0; i<n; i++)
{
int u,v,m;
scanf("%d:(%d)",&u,&m);
for(int j=0; j<m; j++)
{
scanf("%d",&v);
h[v]++;//记录入度个数
build_edge(u,v);
}
}
int root;
for(int i=1; i<=n; i++)//查找根节点
if(!h[i])
{
root=i;
break;
}
int nn;
scanf("%d",&nn);
for(int i=0; i<nn; i++)//记录询问
{
int u,v;
scanf(" (%d %d)",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
Trajan(root);
for(int i=1; i<=n; i++)//输出个数不为0的祖先
{
if(inq[i])
printf("%d:%d\n",i,inq[i]);
}
}
return 0;
}