并查集有两个功能:合并集合、查询祖宗节点
优化方式:路径压缩,按秩合并
记录每个集合的大小,绑定到根节点。记录每个点到根节点的距离,绑定到子节点
并查集的高级应用:扩展并查集、带权并查集
1250. 格子游戏 - AcWing题库
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 40010;
int n, m;
int f[N];
int a[N];
int get(int x, int y)
{
return x * n + y;
}
int find(int x)
{
if(f[x] == x) return x;
return f[x] = find(f[x]);
}
int main()
{
cin >> n >> m;
for(int i = 0; i < n * n; i ++ ) f[i] = i;
int res = 0;
for(int i = 1; i <= m; i ++ )
{
int x, y;
char t;
cin >> x >> y >> t;
x --, y --;
int a = get(x, y);
int b;
if(t == 'D') b = get(x + 1, y);
else b = get(x, y + 1);
a = find(a), b = find(b);
if(a == b)
{
res = i;
break;
}
f[a] = b;
}
if(res) cout << res;
else cout << "draw";
}
1252. 搭配购买 - AcWing题库
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 10010;
int f[N];
int n, m, V;
int v[N], w[N];
int dp[N];
int find(int x)
{
if(f[x] == x) return x;
return f[x] = find(f[x]);
}
int main()
{
cin >> n >> m >> V;
for(int i = 1; i <= n; i ++ ) f[i] = i;
for(int i = 1; i <= n; i ++ )
cin >> v[i] >> w[i];
for(int i = 1; i <= m; i ++ )
{
int a, b;
cin >> a >> b;
a = find(a);
b = find(b);
if(a != b)
{
f[a] = b;
w[b] += w[a];
v[b] += v[a];
}
}
for(int i = 1; i <= n; i ++ )
if(f[i] == i)
for(int j = V; j >= v[i]; j -- )
{
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}
cout << dp[V];
}
237. 程序自动分析 - AcWing题库
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100000;
int f[2 * N + 100];
int a1[N + 100], b1[N + 100], c1[N + 100];
int find(int x)
{
if(f[x] == x) return x;
return f[x] = find(f[x]);
}
int main()
{
int t; cin >> t;
while(t -- )
{
vector<int> g1, g2;
int n; cin >> n;
for(int i = 1; i <= 2 * N; i ++ ) f[i] = i;
int flag = true;
int cnt = 0;
unordered_map<int, int> mp;
for(int i = 1; i <= n; i ++ )
{
cin >> a1[i] >> b1[i] >> c1[i];
if(c1[i]) g1.push_back(i);
else g2.push_back(i);
if(!mp[a1[i]])//没有a[i];
mp[a1[i]] = ++ cnt;
if(!mp[b1[i]])//没有b[i];
mp[b1[i]] = ++ cnt;
}
for(int i = 0; i < g1.size(); i ++ )
{
int a = mp[a1[g1[i]]], b = mp[b1[g1[i]]];
a = find(a);
b = find(b);
f[a] = b;
}
for(int i = 0; i < g2.size(); i ++ )
{
int a = mp[a1[g2[i]]], b = mp[b1[g2[i]]];
a = find(a);
b = find(b);
if(a == b) flag = false;
}
if(flag) cout << "YES" << endl;
else cout << "NO" << endl;
}
}
238. 银河英雄传说 - AcWing题库
//询问相隔多少战舰
//需要维护集合大小和到祖宗的距离
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 30010;
int m;
int f[N], s[N], d[N];
int find(int x)
{
if(f[x] == x) return x;
int root = find(f[x]);
d[x] += d[f[x]];
return f[x] = root;
}
int main()
{
cin >> m;
for(int i = 1; i < N; i ++ )
{
f[i] = i;
s[i] = 1;
}
for(int i = 1; i <= m; i ++ )
{
char t;
int a, b;
cin >> t >> a >> b;
if(t == 'M')
{
a = find(a);
b = find(b);
d[a] = s[b];
s[b] += s[a];
f[a] = b;
}
else
{
int fa = find(a);
int fb = find(b);
//不能把a、b变成他的祖宗
if(fa != fb) puts("-1");
else printf("%d\n", max(0, abs(d[a] - d[b]) - 1));
}
}
}