带花树小记
又因为不会带花树被全机房薄纱了!
匈牙利做的二分图匹配是带花树的基础,其核心在于寻找增广路,而二分图和一般图的最大区别就是存在奇环,那么带花树的核心也即如何处理奇环。
我们还是枚举每个点找增广路,从每个点出发 BFS,设起点为黑点,增广到的点为白点。如果这个白点没有匹配点,那么就找到了一条增广路,结束。否则如果这个白点没有遍历过,那么将这个白点的匹配点设为黑点,扔到队列里面继续 BFS。
如果这个点已经被遍历过了,且是白点,说明我们找到了一个偶环。一个长度为 \(2k\) 的偶环只能产生 \(k\) 对匹配,而我们现在已经有了 \(k\) 对匹配,因此增广路取反不会增加匹配的对数,可以不用管。如果是一个黑点,说明找到了一个奇环,一个长度为 \(2k+1\) 的奇环也只能产生 \(k\) 对匹配,但是多出来的一个点是灵活的,现在环上已经有了 \(k\) 对匹配,因此我们的目标就是确定多出来的点的位置。
这个环上多出来了一个点显然是黑点,并且环上的所有点都可以成为这个点,因此我们将整个环都染成黑点,这个操作称为开花。
具体的,首先我们找到 \(x,y\) 在 BFS 树上的 LCA,然后将这整个环看成都是黑点继续匹配,并且将其中的白点入队增广。同时,为了能在找到增广路以后对路径取反,我们还需要维护每个白点的前驱 \(pre_x\)。
但是问题来了,在奇环上都是黑点,怎么维护 \(pre_x\) 呢?
注意到环上是匹配边和非匹配边相间的,而如果一个原来的白点增广成功,那么这个白点会从它的匹配点开始,往下绕一圈,如果一个黑点增广成功,那么会往上翻转直至 LCA 处。
由于白点和黑点的反转方向是不同的,因此我们将环上的 \(pre\) 全部建成双向边,这样的话手玩一下就可以发现满足题意。于是我们得到了一个 \(O(nm^2)\) 的做法。
但是这个做法看上去非常劣,考虑如何优化。可以用并查集加速缩花的过程。发现实际上如果我们将花看作一个点,那么求 LCA 的时候大力跳过是没有关系的,而缩花的过程可以看作启发式合并,因此总复杂度是 \(O(nm\log n)\) 的,而且还跑不满。

浙公网安备 33010602011771号