Tarjan发明的又一种算法,与连通性没关系
一种离线算法,需要等到所有查询都给出后统一进行处理和求解,但是时间效率非常高,时间复杂度最低可以达到
主要思路是,维护一个并查集,从根节点开始 dfs 。设查询的一对点为 u 和 v , u 比 v 更早被遍历,当遍历完 u 回溯到某个祖先 p 时发现两点同属于以 p 为根的子树中,节点 p 即为 u , v 的最近公共祖先 LCA 。
形象地理解,最初每个节点独属于一个集合,每次回溯时把这个集合合并到父节点所在集合里,已回溯的最浅祖先节点为“队长”。找到点 v 时发现点 u 已经合并到能 dfs 到 v 的集合里了,此时 u 的队长即为最近公共祖先(此时它还不是 v 的队长,v 还未回溯完毕)
代码框架如下:
void tarjan(int u,int fa){
for(auto v : vec[u]){//dfs 邻接表存图
if(v == fa) continue;
vis[v] = true;//已访问
tarjan(v,u);
f[find(v)] = find(u);//合并并查集,将子节点合并至父节点
}
for(auto v : Q[u])//询问 Q数组存对点信息
if(vis[v])//对点在当前子树内
ans[make_pair(u,v)] = find(v);//LCA
}