并查集
概念
并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题(即所谓的并、查)。比如说,我们可以用并查集来判断一个森林中有几棵树、某个节点是否属于某棵树等。
实现
属性: pre[]:记录每个结点的先驱结点
size[]:记录当前结点所属集合的大小 count:记录连通分量的个数 方法:
查找代表元(find):查找当前结点所属集合的代表元,树形结构,我们可以通过pre逐层向上查找,一直找到根节点即为当前集合的代表元。
(这里的代表元就是一个集合中的代表元素,如果两个元素的代表元相同,则这两个元素属于同一集合)
1 2 3 4
| int find(int x){ if (pre[x] == x) return x; return pre[x] = find(pre[x]); }
|
合并(connect):合并两个结点,我们通过pre[y]=x,将y结点连接到x上,这里我们为了减少find函数的迭代次数,我们总是把小的集合连接到大的集合上。
1 2 3 4 5 6 7 8 9 10 11 12
| bool connect(int x, int y){ x = find(x); y = find(y); if (x == y) return false; if (size[x] < size[y]) swap(x, y); pre[y] = x; size[x] += size[y]; count--; return true; }
|
查询(isconnect):判断两个结点是否属于同一集合
1 2 3
| bool isconnect(int x, int y){ return find(x) == find(y); }
|
断开连接(disconnect):将当前结点断开与其上层节点的连接
1 2 3
| void disconnect(int x){ pre[x] = x; }
|
模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| class UnionFind { public: vector<int> pre; vector<int> size; int count; UnionFind(int n) { count = n; pre.resize(n); size.resize(n, 1); for (int i = 0; i < n; i++) { pre[i] = i; } } int find(int x) { if (pre[x] == x) return x; return pre[x] = find(pre[x]); } bool isconnect(int x, int y) { return find(x) == find(y); } bool connect(int x, int y) { x = find(x); y = find(y); if (x == y) return false; if (size[x] < size[y]) swap(x, y); pre[y] = x; size[x] += size[y]; count--; return true; } void disconnect(int x) { pre[x] = x; } };
|
模板
P3367 【模板】并查集
- 洛谷 | 计算机科学教育新生态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| int pre[MAX],n,t;
void init(){ for(int i = 1 ; i <= n ; i ++){ pre[i] = i; } }
int find(int x){ if(pre[x] == x) return x; else return pre[x] = find(pre[x]); }
void Union(int x,int y){ int fx = find(x); int fy = find(y); if(fx != fy) pre[fx] = fy; }
int main(void){ cin>>n>>t; init(); while(t--){ int z,x,y; cin>>z>>x>>y; if(z == 1){ Union(x,y); }else{ cout<<(find(x) == find(y)?"Y":"N")<<endl; } } return 0; }
|