双极定向

给你一个无向连通图,把它定向成 DAG ,要求只有 \(s\) 没入度,只有 \(t\) 没出度。

要求 \(O(n+m)\)


首先题目有若干种等价表述,比如 P9394\(k=1\) 和本题相同。

注意到并不是所有图都能做。注意到有解当且仅当缩完点双是条链,或者说连上 \((s,t)\) 后是点双。

为什么?

点双 \(\Rightarrow\) 有解:下面有构造性证明。

有解 \(\Rightarrow\) 点双:假设有个非点双有解,那么一定有个割点 \(x\) ,考虑把 \(x\) 删掉以后不和 \(s,t\) 连通的某个连通块,发现为要么做不到 DAG ,要么会有某个点出度或入度为 \(0\)

然后有若干做法:

  1. 考虑这样一个过程:每次染黑一个点,要求任意时刻黑点和白点分别连通(其实就是 P9394\(k=1\) ),同时还要求第一个点是 \(s\) ,最后一个点是 \(t\) 。一个合法染色顺序就是一个拓扑序,所以只要求合法染色顺序即可。

    考虑直接模拟,复杂度 \(O(nm)\) 。具体正确性分析可看 CF1916 的题解。

  2. 求出耳分解,然后依次加入每个耳,给耳上每条边定同一个方向。双极性是显然满足的,但是为了不成环需要判断耳端点可达性。复杂度 \(O(nm)\) 。具体耳分解相关可以看 这个博客

  3. 注意到:

    1. 可以缩二度点。
    2. 求出 DFS 生成树后,对每个点可以只保留最浅的返租边。
    3. 经过 2 以后,叶子总是二度点。

    一直应用上面 3 个操作,直到剩一条 \(s\)\(t\) 的链。复杂度 \(O(n+m)\)

但是这些做法都过于复杂或者复杂度过高。下面介绍一种简单线性做法,来自 ix35 的题解

首先先用一下之前第一种做法的转化。

然后求出一棵 DFS 生成树,并求出每个点 \(u\) 子树内最浅的返租边 \(low_u\)

考虑这样一个算法:每个点维护一个后继集合,记为 \(L_i\) ,初始把每个点 \(u\) 加入到 \(L_{fa_u}\)\(L_{low_u}\) 中。从 \(s\) 开始 dfs,每到一个点 \(u\) 就依次从深到浅 dfs 所有 \(L_u\) 中的点。把 dfs 的顺序记下来,就得到了一种染色方案。容易发现这只能保证第一个点是 \(s\) ,而最后一点不一定是 \(t\)

在补充这个算法之前,为什么它是对的?

假如上一个染的是 \(u\) ,即将染 \(v\) 。我们即将说明,如果染 \(u\) 的时候合法,那染完 \(v\) 也合法。

  1. 如果 \(v\) 不在 \(u\) 子树内,那么意味着 \(u\) 整个子树已经全黑了,此时算法 dfs 回溯了一层。(这是因为 \(L_u\) 包含了 \(u\) 的所有儿子)

    然后由于 \(u\) 子树全黑了,就可以直接把这个子树割掉,因为它既不会影响黑点之间的连通性,也不会影响白点之间的连通性。

  2. 如果 \(low_v=u\) ,由于 \(v\) 深度最大,所以一定有一条边 \((u,v)\) ,这说明此时黑点连通。同时,\(v\) 的所有儿子 \(x\) 还都满足 \(dp(v)<dp(low_x)<dp(u)\) (其中 \(dp(x)\) 指的是 \(x\) 的深度),这能说明 \(v\) 的所有后代能连到 \(v\) 上面,故也没有破坏白点连通性。

  3. 如果 \(fa_v=u\) ,则意味着不存在 \(low_x=u\) 。黑点显然连通,只要考虑白点。考虑 \(v\) 的儿子 \(x\) ,由于 \(low_x\not=u\) ,只能有 \(dp(low_x)>dp(u)\) ,所以也不破坏白点连通性。

好,现在我们来解决最后一个点不是 \(t\) 的问题。考虑找一条 \(s\)\(t\) 的链,在执行上面算法时不把链上的元素加入后继集合,然后再最后依次染黑链上的点(并处理可能的后继集合里的点)。这个操作正确性较为显然(考虑每次链上前 \(i\) 个点会染黑第 \(i+1\) 个点 \(x\) 的子树中除了 \(x\) 的部分)。

综上,我们得到了一个复杂度 \(O(n+m)\) 求双极定向的做法。代码实现很简单。

posted @ 2024-04-28 13:36  Z_301  阅读(107)  评论(0)    收藏  举报