并查集最朴素的用法就是用来维护连通性。
然后可以用在 Kruskal 算法中求 MST。
并查集还可以维护更多信息~~
1)加上顺序
poj 1456,需要找 1 - i 格子中最靠右的空格。
让每个节点的根代表往左找到的第一个空格。
当一个空格子被占用,维护操作只需要
pa[pos] = pos - 1
PS:这道题也可以不用并查集,用二分来找
2)为点加上权值
zoj 3261
可以看成是 graph and queries 的简化版,在那道题中,需要找联通分量中的第k大,这里只需要维护最大。
所以,让根节点为最大的节点就行了。
3)为边加上权值
边加上权值,边权就相当于 节点和根的函数值,或者说关系。
(其实应该可以用数学语言精炼描述。。无奈。。 = =
不过,可以看下这个描述,我觉得很准确
这一类题,必须首先提起的就是 POJ 1182 食物链,理解此题,这种函数思想就可以入门了。
// POJ 1182 食物链
int pa[N], r[N], n;
void init() {
memset(r, 0, sizeof(r));
rep(i, 0, n-1) pa[i] = i;
}
int Find(int x) {
if ( x == pa[x] ) return x;
int fa = pa[x];
pa[x] = Find(pa[x]);
r[x] = (r[x] + r[fa]) % 3;
return pa[x];
}
bool unite(int x, int y, int d) {
int px = Find(x), py = Find(y);
if ( px == py ) {
if ( d == 1 ) return r[x] == r[y];
return ( r[x] - r[y] + 3 ) % 3 == 1;
}
pa[px] = py;
if ( d == 1 ) {
r[px] = ( r[y] - r[x] + 3 ) % 3;
} else {
r[px] = ( r[y] - r[x] + 4 ) % 3;
}
return true;
}
例如
POJ 1733 Parity game
f(u, find(u)) = (区间
hdu 3038 How Many Answers Are Wrong
这道题中还要注意合并的顺序
f(u, find(u)) = (区间
然后就是照单刷一些题