并查集¶
https://blog.csdn.net/u013480600/article/category/1858379
https://www.luogu.com.cn/training/1010
连通性判断 P1197 [JSOI2008]星球大战 P1783 海滩防御 非加权维护 P1525 关押罪犯 P2024 [NOI2001]食物链 加权维护 P1196 [NOI2002]银河英雄传说 P2342 [USACO04OPEN]Cube Stacking G
基础并查集¶
两个最主要的功能:
- 查询元素a和元素b是否属于同一组
- 合并元素a和元素b所在的组
并查集是利用树形结构实现的,但是采用数组进行模拟。查询采用递归的方法去实现,合并则是根据高度(或秩rank)来进行合并。另外为了保证查询的平均时间复杂度为线性,就需要去防止最坏情况的发生,所以需要路径压缩的操作。
并查集的实现:
int n = 1005;
vector<int> parent(n);
vector<int> rank(n); //树的高度
//初始化
void init()
{
for (int i = 0; i < n; ++i) {
parent[i] = i;
}
}
//查询操作
int find(int x)
{
if (parent[x] == x) return x;
else return parent[x] = find(parent[x]);
}
//合并x和y所属的集合
void unite(int x, int y)
{
x = find(x);
y = find(y);
//如果x和y所属的集合相同,无需操作
if (x == y) return;
//按高度合并
if (rank[x] < rank[y]) parent[x] = y;
else {
parent[y] = x;
if (rank[x] == rank[y]) ++rank[x];
}
}
//查询x和y是否属于同一个集合
bool isSame(int x, int y)
{
return find(x) == find(y);
}
扩展域¶
《挑战程序设计竞赛》的食物链开三倍空间的方法。
带权并查集¶
带权并查集是结点存有权值信息的并查集;当两个元素之间的关系可以量化,并且关系可以合并时,可以使用带权并查集来维护元素之间的关系;带权并查集每个元素的权通常描述其与并查集中祖先的关;带权并查集可以推算集合内点的关系,而一般并查集只能判断属于某个集合。
仅以POJ 1182食物链为例来了解带全并查集的基本操作。
从一个结点x指向另一个结点y,表明x和y有联系,相对关系用r来表示。0表示x和y是同类,1表示x吃y,2表示x被y吃。新开一个名为rela
的数组,代表结点之间的关系(relation,不这么命名是因为会和标准库函数名冲突),设x所属的集合的根节点为xRoot
,则rela[x]
代表x对xRoot
的关系。
查询操作。已知x和y存在相对关系,关系从y指向x,并且知道x和根节点xRoot
的关系,那么当查询y的时候,按照路径压缩的要求,需要将y的根节点也设为xRoot
,并且需要去更新y和根节点的关系,即rela[y]
。关系是不会因为经过中间的一些结点(比如x)而改变,设y对x的关系为r,那么应有r + rela[x] = rela[y]
。为了始终用0,1,2表示关系,需要对结果取模。那么关键问题来了,r是多少,其实在没有去改变y的根节点之前,y的根节点是x,所以会有原来的r = rela[y]
,那么更新的时候需要变动两个:一个是修改根节点,和基础并查集一致,另一个就是修改关系,rela[y] = (rela[x] + rela[y]) % 3
。
查询相对关系。如果已知x和y属于同一集合,那么可知x和y的根节点相同,现在想知道x对y的关系。根据图中关系可以得出:r + rela[y] = rela[x]
,则r = rela[x] - rela[y]
,为了防止r出现负数,那么r = (rela[x] - rela[y] + 3) % 3
。
合并操作。现在已经知道x和y属于同一集合,现在需要对两个集合的根节点进行合并,假设是把x的根节点合并到y,修改parent
的操作和基础并查集一致。从图中可以得到关系:r + rela[y] = rela[x] + rela[parent[x]]
,显然需要更新的是rela[parent[x]]
,为了防止出现负数,则有:rela[parent[x]] = (r+ rela[y] - rela[x] + 3) % 3
典型题目¶
邝斌带你飞系列:
- 洛谷 P3367 模板-并查集(基础并查集)
- POJ 2236 Wireless Network(基础并查集)
- POJ 1182 食物链(带权并查集或基础并查集开3倍空间)
- HDU 1213 How Many Tables(基础并查集)
- POJ 1703 find them,Catch them(基础并查集开双倍空间)
- HihoCoder-1515-分数调查(带权并查集)
- HDU 3038 How Many Answers Are Wrong(带权并查集)
- POJ 2492 A Bug's Life(路径压缩 + 并查集)
- 洛谷 P3402 可持久化并查集
- HDU 4496 D-CITY
- ZOJ 3261 Connection in Galaxy(并查集 + 离线处理)
- HDU 3635 Dragon Balls (并查集 + 路径压缩)
- POJ 1988 Cubes Stacking (路径压缩 + 并查集)
- POJ 1733 Parity Game(路径压缩 + 并查集 + 离散化)
- POJ 1417 True Liars(路径压缩 + 并查集 + DP背包)
- POJ 1984 Navigation Nightmare(路径压缩 + 并查集)
- POJ 2912 Rochambeau(路径压缩 + 并查集)
- POJ 1456 Supermarket(贪心算法,并查集优化)
- UVA 1329 Corporative Network(路径压缩 + 并查集)
- ZOJ 3321 Circle(并查集)
- UVA 1160 X-Plosives(并查集)
- HDU 1213 How Many Tables
- HDU 1198 Farm Irrigation
- POJ 1611 The Suspects
- HDU 1272 小希的迷宫(并查集:判断连通且结构为树)
- ZOJ 3659 Conquera New Region(并查集:维护根节点信息)
- HDU 1232 畅通工程
- HDU 1325 = POJ 1308 Is it A Tree
- POJ 2524 Ubiquitous Religions
- POJ 2253 Frogger(并查集 + 二分)