数据结构---并查集基础

并查集

三个字概括:找老大

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;
}
posted @ 2026-01-20 20:22  不太会a  阅读(0)  评论(0)    收藏  举报