并查集
init初始化操作:
让每个结点成为一个集合。
void init(int n) {
for (int i = 1; i <= n; i++) {
f[i] = i;
}
}
getf得到一个结点所在集合的值:
int getf(int v) {
if (v == f[v])
return v;
else {
f[v] = getf(f[v]);
return f[v];
}
}
合并两个集合:
将集合a的值变成集合b的值。
void Merge(int u, int v) {
int t1 = getf(u);
int t2 = getf(v);
if (t1 != t2) {
f[t1] = t2;
}
}
带权并查集
每个结点都会记录它和父节点之间的权值,记为val[x]。
在路径压缩的过程中,不仅仅需要更新父节点,还要更新这个节点到根节点的权值,根据递归的思想,处理这个节点之前,都要处理它的父节点,根据递归,处理这个节点的时候他的父节点一定连在了根节点上,所以如果路径压缩,只需要在这个节点权值基础上加上父节点到根节点的权值即可,所以我们在每一步递归调用之前,存储好父节点的标号,在递归之后实现权值更改操作。
int getf(int x)
{
if (x != p[x])
{
int t = p[x];
p[x] = getf(p[x]);
val[x] += val[t];
}
return p[x];
}
两颗树合并的过程,也要处理权值问题。
val[x]是x到f[x]的权值,val[y]是y到f[y]的权值,s是x到y的权值,val[px]代表新连接的边的权值。
void Merge(int x, int y) {
int px = getf(x);
int py = getf(y);
if (px != py) {
f[px] = py;
val[px] = -val[x] + val[y] + s;
}
}
并查集判断连通性
待补