关于并查集的一些套路和用途
并查集的模板(加上了路径压缩)
int find(int x)
{
if (x != p[x]) p[x] = find(p[x]);
return p[x];
}
1.并查集常被用于判断一张图是否连通,或是连通的最小代价(也就是最小生成树问题)或是最小步数
例如:
P1111 修复公路
P1546 [USACO3.1]最短网络 Agri-Net
#include <iostream>
#include <algorithm>
#include <string>
#include <map>
using namespace std;
typedef pair<int, int> PII;
const int N = 200010, INF = 1e9;
int p[N], sz[N];
struct S{
int x, y, z;
}s[N];
int find(int x)
{
if (x != p[x]) p[x] = find(p[x]);
return p[x];
}
bool cmp(S a, S b)
{
return a.z < b.z;
}
void solve()
{
int n;
cin >> n;
int ans = 0;
int idx = 0;
for (int i = 1; i <= 110; i ++) p[i] = i;
for (int i = 1; i <= n; i ++)
{
for (int j = 1; j <= n; j ++)
{
cin >> s[++ idx].z;
s[idx].y = j;
s[idx].x = i;
}
}
sort(s + 1, s + 1 + idx, cmp);
for (int i = 1; i <= idx; i ++)
{
int px = find(s[i].x), py = find(s[i].y);
if (px != py)
{
p[px] = py;
ans += s[i].z;
}
}
cout << ans << endl;
}
int main()
{
int t = 1;
while (t --)
{
solve();
}
return 0;
}
2.判断去掉某边后,是否还能构成连通图
例如:
P1656 炸铁路
P6121 [USACO16OPEN]Closing the Farm G
#include <iostream>
#include <algorithm>
#include <string>
#include <map>
#include <cstring>
#include <queue>
using namespace std;
typedef pair<int, int> PII;
const int N = 200010, INF = 1e9, M = N / 2;
int p[N], sz[N];
int idx, ans[N], tmp[N], h[N];
bool st[N];
struct Edge{
int from;
int to;
int next;
}e[2 * N];
int find(int x)
{
return x == p[x] ? p[x] : p[x] = find(p[x]);
}
void add(int x, int y)
{
e[++ idx].from = x;
e[idx].to = y;
e[idx].next = h[x];
h[x] = idx;
}
void solve()
{
int n, m;
cin >> n >> m;
memset(h, -1, sizeof h);
for (int i = 1; i <= n; i ++) p[i] = i;
for (int i = 1; i <= m; i ++)
{
int u, v;
cin >> u >> v;
add(u, v);
add(v, u);
}
for (int i = 1; i <= n; i ++)
{
cin >> tmp[i];
}
ans[n] = 1;
st[tmp[n]] = 1;
int k = 0;
for (int i = n - 1; i >= 1; i --)
{
st[tmp[i]] = 1;
for (int j = h[tmp[i]]; j; j = e[j].next)
{
if (st[e[j].to] == 1)
{
int px = find(tmp[i]), py = find(e[j].to);
if (px != py)
{
k ++;
p[px] = py;
}
}
}
if (k == n - i) ans[i] = 1;
else ans[i] = 0;
}
for (int i = 1; i <= n; i ++)
if (ans[i]) cout << "YES" << endl;
else cout << "NO" << endl;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
while (t --)
{
solve();
}
return 0;
}
3.判断闭环内元素个数
例如:
P2661 [NOIP2015 提高组] 信息传递
#include <iostream>
#include <algorithm>
#include <string>
#include <map>
#include <cstring>
#include <queue>
#include <cmath>
#include <stack>
#include <iomanip>
using namespace std;
typedef pair<int, int> PII;
const int N = 200010, INF = 1e9, M = N / 2;
int p[N], d[N];
int find(int x)
{
if (x != p[x])
{
int root = p[x];
p[x] = find(p[x]);
d[x] += d[root];
}
return p[x];
}
void solve()
{
int n;
cin >> n;
for (int i = 1; i <= n; i ++) p[i] = i;
int ans = INF;
for (int i = 1; i <= n; i ++)
{
int x;
cin >> x;
int px = find(i), py = find(x);
if (px != py)
{
p[px] = py;
d[i] = d[x] + 1;
}
else {
ans = min(d[x] + d[i] + 1, ans);
}
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
while (t --)
{
solve();
}
return 0;
}
4.带权并查集
P6691 选择题

浙公网安备 33010602011771号