Tarjan求解LCA

Tarjan发明的又一种算法,与连通性没关系

一种离线算法,需要等到所有查询都给出后统一进行处理和求解,但是时间效率非常高,时间复杂度最低可以达到 $O((n+q)×Alpha(n))$

主要思路是,维护一个并查集,从根节点开始 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
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值