【两个双连通分量和O(nlogn)~O(logn)在线求LCA的tarjan算法】

小囧了一下,双连通分量有两种我是前两天才知道的

相关概念参考byv牛的blog,这里记几个关键的点

桥就是dfn[i] < low[j]的边(i, j)

割点就是它发出去的边(i, j)中至少一条满足dfn[i] <= low[j](这里是要取等号的)

我一般求的是所谓 边双连通分量,实际上就是把桥去掉之后还在一起的点的集合

而这里还有一个 点双连通分量,这个东西实际上就是差不多把割点去掉之后还在一起的边的集合

ps:点 <=> 边,这个东西为什么不反过来叫呢?

求法的话差不多,都是用tarjan算法,不过求边双连通分量时还要开一个边的栈,碰到一条满足dfn[i] <= low[j]的边就退一次栈一直退到这条边

还有一个东西就是那个求LCA的算法

它用到的主要思想就是倍增,求出每个点往上跳2^j步后的点,从而使一个点可以以O(logn)的复杂度跳到它的某个祖先跟前

但是怎么每次询问具体怎么做呢?

第一个简陋的想法就是二分lca的深度,再跳,再判——但是这样一来,每次询问的复杂度就达到了O((logn)^2),不太理想

有直接logn的方法吗?显然是有的,先让询问的点对(i, j)中深度大的先跳到两个深度一样的地方,再两个一起跳,这样就是O(logn)的复杂度了,不过常数乘了个2

有只跳一轮的方法吗?暂时还没想到

另外,我为什么在这里提一下这个并不是特别漂亮的LCA的方法呢?

尽管这个方法无论是时间还是空间都不是最优的,但它有一个巨大的优势,在线和可扩展

ghy大牛论文中利用欧拉序列求lca的方法难以扩展,无法在求lca的同时求一些附加信息诸如路径上的权值和之类的

有一个离线O(n+q)利用了并查集的方法虽然可扩展性比较强,可是却是离线的

还有一点,这个方法所需求的信息很少,仅用父亲表示法的树就能求出所有东西,而其他的方法都需要把树用邻接表存下来才行

这个优势其实是相当有用的——在一些“扩展版”的树中要求lca的时候这个方法就有着编程复杂度小的优势了

比方说在cactus图(仙人掌图,图中的每条点最多属于一个简单环)中,或是yt的最短路那道题中的每条边最多属于一个简单环的图,如果把一个点能扩展出的块中的点的父亲都改成它,最后这个图就成了一棵树

我们实际上比较容易求出的是最后那棵树的父亲表示法,如果再要重建一个邻接表无疑就麻烦了,这个时候用这个方法求lca就很方便了

 

附集训队yt-最短路的代码,包含了上面说的大部分算法

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值