LCA算法有在线算法也有离线算法,所谓的在线算法就是实时性的,比方说,给你一个输入,算法就给出一个输出,就像是http请求,请求网页一样。给一个实时的请求,就返回给你一个请求的网页。而离线算法则是要求一次性读入所有的请求,然后在统一得处理。而在处理的过程中不一定是按照请求的输入顺序来处理的。说不定后输入的请求在算法的执行过程中是被先处理的。
Tarjan算法基于深度优先搜索的框架,对于新搜索到的一个结点,首先创建由这个结点构成的集合,再对当前结点的每一个子树进行搜索,每搜索完一棵子树,则可确定子树内的LCA询问都已解决。其他的LCA询问的结果必然在这个子树之外,这时把子树所形成的集合与当前结点的集合合并,并将当前结点设为这个集合的祖先。之后继续搜索下一棵子树,直到当前结点的所有子树搜索完。这时把当前结点也设为已被检查过的,同时可以处理有关当前结点的LCA询问,如果有一个从当前结点到结点v的询问,且v已被检查过,则由于进行的是深度优先搜索,当前结点与v的最近公共祖先一定还没有被检查,而这个最近公共祖先的包涵v的子树一定已经搜索过了,那么这个最近公共祖先一定是v所在集合的祖先。
int findp(int x)
{
if(pnt[x]!=x) pnt[x] = findp(pnt[x]);
return pnt[x];
}
int unionset(int x,int y)
{
int x = findp(x);
int y = findp(y);
pnt[y] = x;
} //以上两步是并查集的操作,没啥过多解释。
void Lcancestor(int parent)
{
pnt[parent] = parent; //当访问到一个点的时候,先将其自己形成一个集合
ancestor[findp(parent)] = parent;
for(int i=0;i<=child[parent].size();i++)
{ //接着一次访问节点的子节点,
Lcancestor(child[parent][i]); //依次对子节点进行访问。
unionset(parent,child[parent][i]); //在处理完后,将子节点的集合链接到父节点
ancestor[findp(child[parent][i])] = parent;
} //实际上这一步起到了并查集的压缩节点的作用。这样可以将查询降低到O(1)
color[parent] = true;
if( parent = first && color[second] ) //这里的first和second主要针对的是查询的每次操作时输入的两个数。
{
ans = ancestor[findp(second)] ;
}
if( parent = second && color[first] )
{
ans = ancestor[findp(first)];
}
}