【BZOJ4025】二分图(可撤销并查集+线段树分治)

本文介绍了如何利用可撤销并查集和线段树分治法解决BZOJ4025题目的二分图问题。首先通过保证边的出现时间段不交叉,确保不会形成奇环。接着,讨论了在边只出现不消失的情况下,如何通过并查集维护连通性和距离奇偶性。当边可以消失时,使用撤销栈记录并查集的修改。最后,引入线段树分治策略,优化区间拆分,使得每个边最多被加入或撤销logT次,总复杂度达到O(nlog^2n)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

BZOJ4025

分析:

定理:一个图是二分图的充要条件是不存在奇环。

先考虑一个弱化的问题:保证所有边出现的时间段不会交叉,只会包含或相离。

还是不会?再考虑一个更弱化的问题:边只会出现不会消失。

当加边的时候,若 ( u , v ) (u,v) (u,v)不连通:一定不会构成奇环,将它加入。

( u , v ) (u,v) (u,v)已经联通,则不加入这条边,而是查询 u u u v v v两点间的距离。若为偶数则加上这条边后会形成奇环。一个奇环不可能分成数个偶环,所以从此以后都不再是二分图。若为奇数则直接忽略这条边,因为如果将来某条边会与这条边形成奇环,则用当前 u u u v v v之间的路径(长度为奇数)替代这条边(长度为 1 1 1)同样也会形成奇环。

按照上述做法,最终我们会造出原图的一棵生成树。

用带权并查集维护连通性和两点间距离的奇偶性。记录每个结点到它并查集上的父亲的距离(注意并查集的形态不一定和原树相同。加入边 ( u , v ) (u,v) (u,v)时在并查集上连接的是它们所在集合的根 f ( u ) f(u) f(u) f ( v ) f(v) f(v))。

当加入边 ( u , v ) (u,v) (u,v)时,设 u u u v v v所在并查集的根为 x x x y y y,要把 x x x合并进 y y y x x x的父亲被赋值成 y y y。脑补一下此时 x x x y y y的路径是 x x x u u u,边 ( u , v ) (u,v) (u,v),然后 v v v y y y,所以暴力爬链分别求出 u u u v v v到根的距离,异或起来再异或 1 1 1就是 x x x到它的父亲 y y y的距离。

查询时把两点到根距离异或起来就是它们之间距离的奇偶性。(树上两点间路径是唯一的,多余的路径被走了偶数次不影响奇偶性。)

如果边会消失呢?删除一条已经被加入的边时,由于保证不存在出现时间交叉的情况,删除的一定是最晚加入的边。因此把对并查集的每次修改都存到一个栈中,撤销的时候按修改顺序的逆序复原即可。这种神奇的数据结构叫“可撤销并查集”

为了保证 O ( log ⁡ n ) O(\log n) O(logn)的时间复杂度,需要按秩合并。同时由于要可撤销,不能路径压缩破坏树形。放上可撤销并查集的代码。

namespace UFS
{
   
   
	int fa[N], top, rk[N];
	bool dis[N];
	struct node
	{
   
   
		int x, y, f, r;
		bool d;
	}stack[N];
	int f(const int x)
	{
   
   
		return x == fa[x] ? x : f(fa[x]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值