并查集模板

路径压缩+按秩合并

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 const int maxn=500010;
 6 int a[maxn], n;
 7 int fa[maxn];
 8 int rank[maxn];
 9 
10 void init() {
11     for(int i=1;i<=n; i++) {
12         fa[i]=i;
13         rank[i]=0;
14     }
15     return ;
16 }
17 
18 int find(int z) {
19     if(fa[z]!=z) 
20         return fa[z]=find(fa[z]);
21     return fa[z];
22 }
23 
24 void unionn(int x,int y) {
25     x=find(x);
26     y=find(y);
27     if (x==y) return ;
28     if(rank[x]<rank[y]) {
29         fa[x]=y;
30     } 
31     else {
32         fa[y]=x;
33         if (rank[x]==rank[y])
34          rank[x]++;
35     }
36     return;
37 }

 

 

例题

洛谷T3766

//find与fa引发的血案

题目描述

有一个 M 行 N 列的点阵,相邻两点可以相连。一条纵向的连线花费一个单位,一条横向的连线花费两个单位。某些点之间已经有连线了,试问至少还需要花费多少个单位才能使所有的点全部连通。

输入输出格式

输入格式:

 

第一行输入两个正整数 m 和 n。

以下若干行每行四个正整数 x1,y1,x2,y2, 表示第 x1 行第 y1 列的点和第 x2 行第 y2 列的点已经有连线。输入保证|x1-x2|+|y1-y2|=1。

 

输出格式:

 

输出使得连通所有点还需要的最小花费。

 

输入输出样例

输入样例#1:
2 2
1 1 2 1
输出样例#1:
3

说明

30%数据: n*m<=1000

100%数据: m,n<=1000

 

标程

//find与fa引发的血案

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 int m, n, tot, ans;
 5 int fa[1000010]; //father x,y=fa[x*1000+y]
 6 
 7 int find(int z) {
 8     if (fa[z]!=z) fa[z]=find(fa[z]);
 9     return fa[z];
10 }
11 
12 int unionn(int x, int y) {
13     x=find(x);
14     y=find(y);
15     if (x!=y) fa[x]=y;
16 }
17 
18 int main() {
19     cin >> m >> n;
20     int sum = m*n;
21     for (int i=1; i<=sum; i++) fa[i]=i;
22     int x1,y1,x2,y2;
23     while (cin>>x1>>y1>>x2>>y2) {
24         unionn((y1-1)*m+x1,(y2-1)*m+x2);
25     }
26     for (int i=1; i<=sum; i++) 
27         if (fa[i]==i) tot++;
28     if(tot==1) { cout<<ans; return 0; }
29     for (int i=1; i<=n; i++) { //对于每一列A[i] 
30         for (int j=1; j<m; j++) { //枚举a[i][j]&a[i][j+1]是否联通 
31             int k=(i-1)*m+j;
32             if (find(k)!=find(k+1)) {
33                 tot--;
34                 ans++;
35                 unionn(k,k+1);
36             }
37             if (tot==1) { cout<<ans; return 0; }
38         }
39     }
40     for (int i=1; i<n; i++) {
41         if (find((i-1)*m+1)!=find(i*m+1)) {
42              tot--;
43             ans+=2;
44             unionn((i-1)*m+1,i*m+1);
45         }
46         if (tot==1) { cout<<ans; return 0; }
47     }
48     cout<<"0";
49     return 0;
50 }
posted @ 2017-05-06 11:47  3918张佳  阅读(206)  评论(0编辑  收藏  举报