ARC092D Two Faced Edges

题意:给出一张 个点 条边的有向图,保证不存在重边和自环。

对于每条边,判断将其反向后(其他边不变),图中强连通分量的数量是否改变。

,时限


对于边 ,若将其反向:

  • 在同一个强连通分量内。

    强连通分量个数不可能增加,但该强连通分量可能被破坏。

    若图中存在一条 的路径,且不含该边,则不会破坏,反之则会。

  • 不在同一个强连通分量内。

    若图中存在一条 的路径,且不含该边,则会增加一个强连通分量,反之无变化。

表示“ 在同一个强连通分量内”, 表示图中存在 的路径,且不含边

综上所述,只有 两者之一成立,边 的答案才为 ,否则为

对于 ,容易使用 Tarjan 算法求出。问题的核心在于 的求解。

算法一

考虑对于每个 分别求出

开始 dfs ,将 的边表顺序翻转,再次 dfs。

若点 在两个 dfs 树中深度均为 ,则说明 ,否则

证明

,则点 在两个 dfs 树中深度显然均为

下证点 在两个 dfs 树中深度均为 时, 。即 在两个 dfs 树中深度不可能同时为

时,存在另一条不走 的路径能从 ,记该路径的第一条边为

在两次 dfs 中,必然恰有一次先考虑 而后考虑 ,由于 dfs 的特性,一定会从 进而访问到 。后面考虑 时,就不会将其加入 dfs 树。

算法二

仍考虑对于每个 分别求出

对于某个 当且仅当存在 ,满足存在简单路径

点删除,将所有直接与 相连的点记为

顺次考虑 ,从 开始搜索(不重复遍历之前搜过的点),所有搜到的点 (除了 本身)都能满足

(这里用 常数较小)

为了处理 的情况,还需反过来再跑一次。

这样的搜索复杂度是 的,瓶颈在于,无论目的地是否被标记过,我们都要再次检查出边。

考虑利用 bitset 进行优化,记目前还未发现 的集合为 ,点 的出边的集合为 。我们搜索时,只需考虑集合 内的元素。

下面的代码段可以用 的代价找出 bitset 内的所有元素。

1
for(int i=T._Find_first(); i!=T.size(); i=T._Find_next(i))

每个点只会被搜索到一次,故复杂度为