数据结构---并查集基础
并查集
三个字概括:找老大
1. 核心定义
一种用来高效管理“元素分组”的数据结构,专门处理“不相交集合”的合并及查询问题。
2. 两个动作
查 (Find) —— 找老大: 递归寻找当前元素的“根节点”(代表元素)。
并 (Union) —— 认干爹: 判断两个元素是否在同一个集合。如果不是,让一个集合的老大,成为另一个集合老大的“下级”。优化(路径压缩): 既然找到了老大,下次直接挂在老大名下,以后一步就能找到,不再一层层汇报。
相关例题
1,星球大战(逆向思维)
洛谷星球大战例题
并查集很难实现删点的操作,所以正难则反,先把k个星球摧毁了。遍历一遍有效的边后,得到当前联通块个数,再从第k个开始重建得到摧毁第k-1个星球后的连通块数量。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
// #define int long long
#define pb push_back
#define eb emplace_back
#define all(x) (x).begin(), (x).end()
using ll = long long;
using pii = pair<int, int>;
using pil = pair<int, long long>;
const int INF = 0x3f3f3f3f;
const int N = 4e5 + 10;
int fa[N];
bool del[N];
vector<int> que;
vector<int> adj[N];
int f(int x)
{
return fa[x] == x ? x : fa[x] = f(fa[x]);
}
void solve()
{
int n, m;
int k;
vector<int> ans;
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
fa[i] = i;
}
for (int i = 1; i <= m; i++)
{
int u, v;
cin >> u >> v;
adj[u].pb(v);
adj[v].pb(u);
}
cin >> k;
for (int i = 1; i <= k; i++)
{
int x;
cin >> x;
que.pb(x);
del[x] = 1;
}
int tot = n - k;
for (int i = 1; i <= n; i++)
{
if (del[i])
continue;
for (int j : adj[i])
{
if (del[j])
continue;
if (f(i) != f(j))
{
fa[f(i)] = f(j);
tot--;
}
}
}
ans.pb(tot);
for (int i = k; i >= 1; i--)
{
int x = que[i - 1];
del[x] = 0;
tot++;
for (int j : adj[x])
{
if (del[j])
continue;
if (f(x) != f(j))
{
fa[f(x)] = f(j);
tot--;
}
}
ans.pb(tot);
}
reverse(all(ans));
// cout << "-------------\n";
for (int i : ans)
{
cout << i << "\n";
}
}
signed main()
{
IOS;
int T;
T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

浙公网安备 33010602011771号