#include <fstream>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
struct Edge
{
int leftEnd;
int rightEnd;
Edge(int x, int y)
{
leftEnd = x;
rightEnd = y;
}
};
void DFS(int src, vector<int> adjList[], int level[], int parent[],
int low[], stack<Edge> &st, vector< vector<int>> &result);
void storeBiconnexComponent(int x, int y, stack<Edge> &st, vector< vector<int> > &result);
int main()
{
int N, M, x, y, i, j;
ifstream f("biconex.in");
f >> N >> M;
vector<int> adjList[N + 1];
for (i = 1; i <= M; i++)
{
f >> x >> y;
adjList[x].push_back(y);
adjList[y].push_back(x);
}
f.close();
int parent[N + 1], level[N + 1], low[N + 1];
for (i = 1; i <= N; i++)
parent[i] = -1;
stack<Edge> st;
vector< vector<int> > result;
for (i = 1; i <= N; i++)
if (parent[i] == -1)
{
parent[i] = i;
DFS(i, adjList, level, parent, low, st, result);
}
result.resize(result.size() + 1);
int line = result.size() - 1;
while (!st.empty())
{
result[line].push_back(st.top().leftEnd);
result[line].push_back(st.top().rightEnd);
st.pop();
}
ofstream g("biconex.out");
for (i = 0; i < result.size(); i++)
{
sort(result[i].begin(), result[i].end());
result[i].erase(unique(result[i].begin(), result[i].end()), result[i].end());
for (j = 0; j < result[i].size(); j++)
g << result[i][j] << " ";
g << "\n";
}
g.close();
return 0;
}
void DFS(int src, vector<int> adjList[], int level[], int parent[],
int low[], stack<Edge> &st, vector< vector<int> > &result)
{
static int time = 0;
level[src] = low[src] = ++time;
int children = 0;
int currentNode, i;
for (i = 0; i < adjList[src].size(); i++)
{
currentNode = adjList[src][i];
if (parent[currentNode] == -1)
{
children++;
parent[currentNode] = src;
st.push(Edge(src, currentNode));
DFS(currentNode, adjList, level, parent, low, st, result);
low[src] = min(low[src], low[currentNode]);
if ((parent[src] == src && children >= 2) || (parent[src] != src && low[currentNode] >= level[src]))
storeBiconnexComponent(src, currentNode, st, result);
}
else if (currentNode != parent[src] && level[currentNode] < low[src])
{
st.push(Edge(src, currentNode));
low[src] = min(low[src], level[currentNode]);
}
}
}
void storeBiconnexComponent(int x, int y, stack<Edge> &st, vector< vector<int> > &result)
{
result.resize(result.size() + 1);
int line = result.size() - 1;
int edgeX, edgeY;
do
{
edgeX = st.top().leftEnd;
edgeY = st.top().rightEnd;
result[line].push_back(edgeX);
result[line].push_back(edgeY);
st.pop();
} while (edgeX != x || edgeY != y);
}