並查集學習
普通並查集
用途:維護一個集合的連通性
不用多說,下面的才是重點
擴充套件域並查集
用途:維護兩個以上的集合的連通性。
經典 例題
對於這個題,我們可以把人分成兩個域:朋友域(\(1\) ~ \(n\))和敵人域(\(n+1\) ~ \(2n\))
- 如果 \(u,v\) 是朋友,直接合並 \(u,v\)。
- 如果 \(u,v\) 是敵人,那麼 \(u\) 和 \(v\) 對映到敵人域中的 \(v+n\) 一定是朋友,所以合併 \(u\),\(v+n\)。(\(u+v\) 和 \(v\) 同理)
最後統計一下連通塊的個數。
# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// # define int long long
# define lc u << 1
# define rc u << 1 | 1
# define fi first
# define se second
inline int read ()
{
int w = 1, s = 0;
char c = getchar ();
for (; c < '0' || c > '9'; w *= (c == '-') ? -1 : 1, c = getchar ());
for (; c >= '0' && c <= '9'; s = 10 * s + (c - '0'), c = getchar ());
return s * w;
}
const int N = 2005;
int n, m;
int fa[N];
int find_fa (int u) { return u == fa[u] ? u : fa[u] = find_fa (fa[u]); }
signed main ()
{
// freopen ("test.in", "r", stdin);
// freopen ("test.out", "w", stdout);
n = read (), m = read ();
for (int i = 1; i <= n * 2; i ++ ) fa[i] = i;
while (m -- )
{
char op; int u, v; scanf (" %c%d%d", &op, &u, &v);
if (op == 'F') fa[find_fa (u)] = find_fa (v);
else
{
fa[find_fa (u + n)] = find_fa (v);
fa[find_fa (v + n)] = find_fa (u);
}
}
int cnt = 0;
for (int i = 1; i <= n; i ++ )
{
if (i == fa[i])
cnt ++ ;
}
printf ("%d\n", cnt);
return 0;
}
帶權並查集
用途:可以在並查集的邊上定義某種權值以及這種權值在路徑壓縮時產生的計算。
一般使用的是 \(d_x\) 表示 \(x\) 到根的距離。
int find_fa (int u)
{
if (u == fa[u]) return u;
int v = find_fa (fa[u]);
d[u] = d[u] + d[fa[u]];
return fa[u] = v;
}