铺垫
并查集,是一种常用的存储和修改集合关系的数据结构。
它以树的方式存储每一个集合,每棵树内的元素都在同一个集合中。
当合并两个集合的时候,把其中一个集合的根成为另一个集合的根的子节点。
必要时,还可以进行路径压缩。
算法实现
在并查集的基础的集合关系之上,同一个集合内的元素和元素之间可能还有进一步的关系 (例如是同性/异性,敌人/朋友,也可以是大/小多少)
那么,简单的并查集就维护不了这样复杂的关系了。
然后,我们可以发现,在并查集的每一条边上加入一个权值
d
i
d_i
di,用于表示第
i
i
i号节点和其父节点之间的关系。
合并
然而,合并的操作就没有那么简单了。
此时,如果节点
x
x
x和节点
y
y
y要进行合并,其父节点分别为
f
x
f_x
fx和
f
y
f_y
fy,要根据
y
=
x
+
a
y=x+a
y=x+a的权值进行合并。
假设
d
f
x
=
k
d_{f_x}=k
dfx=k,
接着,我们可以得到以下的关系:
k
+
d
x
+
a
=
d
y
k+d_x+a=d_y
k+dx+a=dy
移项后可得
k
=
d
y
−
d
x
−
a
k=d_y-d_x-a
k=dy−dx−a
这样就计算出了
f
x
f_x
fx作为子节点后
d
f
x
d_{f_x}
dfx的权值了。
例题
Liars and Truth Tellers
题目中说另一个人讲真话的和那个人是同类,
d
i
d_i
di记作
0
0
0
否则两个人不是同类,
d
i
d_i
di记作
1
1
1
当发现两个人既是同类也不是同类时,就有矛盾了
代码:
(To be continued…)