双极定向
给你一个无向连通图,把它定向成 DAG ,要求只有 \(s\) 没入度,只有 \(t\) 没出度。
要求 \(O(n+m)\)。
首先题目有若干种等价表述,比如 P9394 的 \(k=1\) 和本题相同。
注意到并不是所有图都能做。注意到有解当且仅当缩完点双是条链,或者说连上 \((s,t)\) 后是点双。
为什么?
点双 \(\Rightarrow\) 有解:下面有构造性证明。
有解 \(\Rightarrow\) 点双:假设有个非点双有解,那么一定有个割点 \(x\) ,考虑把 \(x\) 删掉以后不和 \(s,t\) 连通的某个连通块,发现为要么做不到 DAG ,要么会有某个点出度或入度为 \(0\) 。
然后有若干做法:
-
考虑这样一个过程:每次染黑一个点,要求任意时刻黑点和白点分别连通(其实就是 P9394 的 \(k=1\) ),同时还要求第一个点是 \(s\) ,最后一个点是 \(t\) 。一个合法染色顺序就是一个拓扑序,所以只要求合法染色顺序即可。
考虑直接模拟,复杂度 \(O(nm)\) 。具体正确性分析可看 CF1916 的题解。
-
求出耳分解,然后依次加入每个耳,给耳上每条边定同一个方向。双极性是显然满足的,但是为了不成环需要判断耳端点可达性。复杂度 \(O(nm)\) 。具体耳分解相关可以看 这个博客 。
-
注意到:
- 可以缩二度点。
- 求出 DFS 生成树后,对每个点可以只保留最浅的返租边。
- 经过 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\) 也合法。
如果 \(v\) 不在 \(u\) 子树内,那么意味着 \(u\) 整个子树已经全黑了,此时算法 dfs 回溯了一层。(这是因为 \(L_u\) 包含了 \(u\) 的所有儿子)
然后由于 \(u\) 子树全黑了,就可以直接把这个子树割掉,因为它既不会影响黑点之间的连通性,也不会影响白点之间的连通性。
如果 \(low_v=u\) ,由于 \(v\) 深度最大,所以一定有一条边 \((u,v)\) ,这说明此时黑点连通。同时,\(v\) 的所有儿子 \(x\) 还都满足 \(dp(v)<dp(low_x)<dp(u)\) (其中 \(dp(x)\) 指的是 \(x\) 的深度),这能说明 \(v\) 的所有后代能连到 \(v\) 上面,故也没有破坏白点连通性。
如果 \(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)\) 求双极定向的做法。代码实现很简单。

浙公网安备 33010602011771号