fork download
  1. #include <bits/stdc++.h>
  2.  
  3. using namespace std;
  4.  
  5. typedef long long ll;
  6. typedef pair<int, int> ii;
  7.  
  8. const int INF = 1e9;
  9. const ll LINF = 1e18;
  10.  
  11. const int N = 1e5 + 5;
  12.  
  13. int n, m;
  14. vector<int> adj[N];
  15.  
  16. int p[N], sz[N];
  17.  
  18. void initSet() {
  19. for (int u = 1; u <= n; u++) {
  20. p[u] = u;
  21. sz[u] = 1;
  22. }
  23. }
  24.  
  25. int findSet(int u) {
  26. if (p[u] == u) return u;
  27. return p[u] = findSet(p[u]);
  28. }
  29.  
  30. void unionSet(int u, int v) {
  31. u = findSet(u);
  32. v = findSet(v);
  33. if (u == v) return;
  34. if (sz[u] < sz[v]) swap(u, v);
  35. p[v] = u;
  36. sz[u] += sz[v];
  37. }
  38.  
  39. int cnt[N];
  40.  
  41. int main() {
  42. ios::sync_with_stdio(false);
  43. cin.tie(nullptr);
  44. cin >> n >> m;
  45. for (int i = 0; i < m; i++) {
  46. int u, v;
  47. cin >> u >> v;
  48. if (u < v) swap(u, v);
  49. adj[u].push_back(v);
  50. }
  51.  
  52. initSet();
  53.  
  54. int num_cc = n; // Số thành phần liên thông tạo bởi những cạnh có trọng số = 0
  55. set<int> comp; // Danh sách các đỉnh đại diện cho các thành phần liên thông hiện tại
  56.  
  57. for (int u = 1; u <= n; u++) {
  58. for (int v : comp) cnt[v] = 0;
  59.  
  60. for (int v : adj[u]) cnt[findSet(v)]++;
  61.  
  62. vector<int> merged;
  63. for (int v : comp) {
  64. // cnt[v] = Số đỉnh có trong thành phần liên thông do v đại diện có cạnh trọng số = 1 nối đến u
  65. if (cnt[v] < sz[v]) {
  66. unionSet(u, v);
  67. merged.push_back(v);
  68. num_cc--;
  69. }
  70. }
  71.  
  72. for (int v : merged) comp.erase(v);
  73. comp.insert(findSet(u));
  74.  
  75. } // O(nlogn + m)
  76.  
  77. cout << num_cc - 1 << '\n';
  78. }
  79.  
Success #stdin #stdout 0.01s 5868KB
stdin
6 11
1 3
1 4
1 5
1 6
2 3
2 4
2 5
2 6
3 4
3 5
3 6
stdout
2