Cầu khớp

Độ phức tạp: \(O(N+M)\)

#include <bits/stdc++.h>

using namespace std;

struct Edge {
   int x, y;
   bool isUsed, isBridge;
};

const int NODE = 100000;
const int EDGE = 100000;
int numNode, numEdge;
vector<int> adj[NODE];
vector<Edge> edge;
int Time, num[NODE], low[NODE], numChild[NODE];
bool isCut[NODE];

void dfs(int u) {
   num[u] = ++Time;
   low[u] = numNode + 1;
   for (int i : adj[u]) if (!edge[i].isUsed) {
       edge[i].isUsed = true;
       int v = edge[i].x ^ edge[i].y ^ u;
       if (!num[v]) {
           numChild[u]++;
           dfs(v);
           low[u] = min(low[u], low[v]);
           edge[i].isBridge |= num[u] < low[v];
           isCut[u] |= num[u] <= low[v];
       }
       else {
           low[u] = min(low[u], num[v]);
       }
   }
}

void findBridgeAndCut() {
   memset(num, 0, sizeof num);
   memset(low, 0, sizeof low);
   memset(numChild, 0, sizeof numChild);
   memset(isCut, false, sizeof isCut);
   Time = 0;
   for (int i = 1; i <= numNode; ++i) {
       if (!num[i]) {
           dfs(i);
           if (numChild[i] == 1) {
               isCut[i] = false;
           }
       }
   }
}

int main() {
   // các đỉnh có chỉ số từ 1 -> numNode
   cin >> numNode >> numEdge;
   for (int i = 0; i < numEdge; ++i) {
       int x, y; cin >> x >> y;
       adj[x].push_back(edge.size());
       adj[y].push_back(edge.size());
       edge.push_back({x,y});
   }
   findBridgeAndCut();
   cout << "Cut: ";
   for (int i = 1; i <= numNode; ++i) {
       if (isCut[i]) cout << i << ' ';
   }
   cout << '\n';
   cout << "Bridge:\n";
   for (int i = 0; i < numEdge; ++i) {
       if (edge[i].isBridge) {
           cout << edge[i].x << ' ' << edge[i].y << '\n';
       }
   }
   return 0;
}