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 = 2e5 + 5;
  12.  
  13. ll nC2(int n) {
  14. if (n < 2) return 0;
  15. return 1ll * n * (n - 1) / 2;
  16. }
  17.  
  18. int n, m;
  19. vector<int> adj[N];
  20.  
  21. int num_cc; // Số thành phần liên thông
  22. int cnt[N]; // cnt[i] = Số đỉnh có trong thành phần liên thông thứ i
  23.  
  24. int cnt_bridge; // Số cạnh cầu
  25. int tin[N], low[N], timer;
  26. int sz[N]; // sz[u] = Số đỉnh có trong cây con gốc u trên cây dfs
  27.  
  28. void dfs(int u, int p) {
  29. cnt[num_cc]++;
  30. tin[u] = low[u] = ++timer;
  31. sz[u] = 1;
  32.  
  33. for (int v : adj[u]) {
  34. if (v == p) continue;
  35. if (!tin[v]) {
  36. dfs(v, u);
  37. low[u] = min(low[u], low[v]);
  38. sz[u] += sz[v];
  39. if (low[v] > tin[u]) cnt_bridge++;
  40. }
  41. else {
  42. low[u] = min(low[u], tin[v]);
  43. }
  44. }
  45. }
  46.  
  47. int main() {
  48. ios::sync_with_stdio(false);
  49. cin.tie(nullptr);
  50. cin >> n >> m;
  51. for (int i = 0; i < m; i++) {
  52. int u, v;
  53. cin >> u >> v;
  54. adj[u].push_back(v);
  55. adj[v].push_back(u);
  56. }
  57.  
  58. num_cc = 0;
  59. cnt_bridge = 0;
  60. timer = 0;
  61. for (int u = 1; u <= n; u++) {
  62. if (!tin[u]) {
  63. num_cc++;
  64. dfs(u, -1);
  65. }
  66. }
  67.  
  68. // Trường hợp đồ thị có từ 3 thành phần liên thông trở lên thì hiển nhiên không tồn tại kế hoạch cải tổ hợp lệ nào cả
  69. // Nên ta sẽ chỉ xét trường hợp đồ thị có 1 hoặc 2 thành phần liên thông
  70. ll ans = 0;
  71. // Trường hợp đồ thị có 1 thành phần liên thông:
  72. if (num_cc == 1) {
  73. ll m1 = nC2(n) - m; // Số cạnh có thể thêm
  74. // Với mỗi cách xoá cạnh không phải là cầu, ta có m1 cách thêm cạnh
  75. ans = 1ll * (m - cnt_bridge) * m1;
  76. // Còn trường hợp cạnh xoá là cạnh cầu thì đồ thị khi đó sẽ bị tách làm 2 thành phần liên thông
  77. // Ta phải thêm cạnh (u, v) sao cho u thuộc thành phần liên thông này còn v thuộc thành phần liên thông kia
  78. // (lưu ý cạnh (u, v) thêm vào phải khác cạnh vừa bị xoá)
  79. for (int v = 2; v <= n; v++) {
  80. if (low[v] == tin[v]) {
  81. ans += 1ll * sz[v] * (n - sz[v]) - 1;
  82. }
  83. }
  84. }
  85.  
  86. // Trường hợp đồ thị có 2 thành phần liên thông:
  87. // Hiển nhiên ta không được phép xoá cạnh cầu
  88. // Với mỗi cách xoá cạnh không phải là cầu
  89. // thì ta phải thêm cạnh (u, v) sao cho u thuộc thành phần liên thông này còn v thuộc thành phần liên thông kia
  90. if (num_cc == 2) {
  91. ans = 1ll * (m - cnt_bridge) * cnt[1] * (n - cnt[1]);
  92. }
  93.  
  94. cout << ans << '\n';
  95. }
Success #stdin #stdout 0.01s 10108KB
stdin
4 4
1 2
2 3
2 4
3 4
stdout
8