在一棵有根树T中,两个节点u和v的最小公共祖先是指这样的一个节点w,它是u和v的祖先,并且在树T中具有最大深度。
Tarjan思想求LCA是从根节点x开始搜索每一棵子树(节点设为y),那么在回溯回子树根节点y的时候就能保证以该子树的全部节点搜索完了,在每搜索完一个子树,那么该子树内的所有LCA(u,v)的问题都已经解决了,其他的LCA询问肯定在另外的子树上,那么这时就把y放入到合并的集合中,这样y结点和所有y的子树中的结点的最近公共祖先就是y了,节点y和当前还没有遍历的y的兄弟节点和这些兄弟节点的子节点的公共祖先都是y的父亲节点。
LCA伪代码:
LCA(u){
MAKE_SET(u)
ancestor[FIND(u)]= u//设定u所在集合的公共祖先
for( each child v of u in T){
LCA(v)
UNION(u,v)//把节点v生成的子集并入u中
ancestor[FIND(u)]=u//防止采用树形启发式合并使u的集合根(代表)变化
}
flag[u]= 1;
for( each node v such that [u,v] in P )
if( flag[v] )
print "The least common ancestor of 'u' and 'v' is " ancestor[ FIND(v) ]
}
POJ 1330
int anc[N],fa[N],in[N],flag[N],rank[N];
int root;
vector<int>mat[N],qes[N];
void init(int n)
{
memset(anc,0,sizeof(anc));
memset(flag,0,sizeof(flag));
memset(rank,0,sizeof(rank));
memset(in,0,sizeof(in));
for(int i = 0 ; i <= n ; i ++) {
fa[i] = i;
mat[i].clear();
qes[i].clear();
}
for(int i = 1 ; i < n ; i ++)
{
int x,y;
scanf("%d %d",&x,&y);
mat[x].push_back(y);
in[y]++;
}
}
int find(int x)
{
if(x != fa[x]) fa[x] = find(fa[x]);
return fa[x];
}
void link(int x,int y)
{
int a = find(x),b = find(y);
if(rank[a] > rank[b]) fa[b] = a;
else fa[a] = b;
if(rank[a] == rank[b]) rank[b]++;
}
void LCA(int root)
{
anc[find(root)] = root;
for(int i = 0 ; i < mat[root].size() ; i ++)
{
LCA(mat[root][i]);//对以节点mat[root][i]为根节点的子树进行搜索
link(root,mat[root][i]);//用并查集将两节点合并
anc[find(root)] = root;
}
flag[root] = 1;
for(int i = 0 ; i < qes[root].size() ; i ++)
{
if(flag[qes[root][i]])
{
printf("%d\n",anc[find(qes[root][i])]);
return;
}
}
}
int main()
{
int T,n;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
init(n);
int u,v;
scanf("%d %d",&u,&v);
qes[u].push_back(v);
qes[v].push_back(u);
for(int i = 1; i <= n ; i ++)
{
if(in[i] == 0)
{
root = i;
break;
}
}
LCA(root);
}
return 0;
}
lca另一种写法
void LCA(int root) { fa[root] = root; for(int i = 0 ; i < mat[root].size() ; i ++) { if(!flag[mat[root][i]]){ LCA(mat[root][i]);//对以节点mat[root][i]为根节点的子树进行搜索 fa[mat[root][i]] = root; } } flag[root] = 1; for(int i = 0 ; i < qes[root].size() ; i ++) { if(flag[qes[root][i]]) { printf("%d\n",find(qes[root][i])); return; } } }
|