#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <fstream>
#include <algorithm>
using namespace std;
ifstream fin("biconex.in");
ofstream fout("biconex.out");
class Graph {
std::vector<std::vector<int>> Ad;
int nodes; // no of nodes
int edges; // no of edges
int directed; // 1 for directed
public:
Graph(const std::vector<std::pair<int,int>> &ad, int nodes, int edges,int directed);
int getComponents();
void pathTo(int node);
std::stack<int> topSort();
void printSCC(); // print strongly connected components
void printBCC(); //print biconex components
private:
void DFS(int node, std::vector<int> &vis);
void BFS(int node, std::vector<int> &vis);
void topSortDFS(int node, std::vector<int> &vis, std::stack<int> &s);
void dfsSCC(int node,int &idInc, std::vector<int> &id, std::vector<int> &low, std::vector<bool> &onStack, std::stack<int> &s, std::vector< std::vector<int>> &scc); // dfs for scc
std::vector< std::vector<int>> getSCC(); // returns scc with tarjan
void dfsBCC(int node, int parent, int &time, std::vector<int> &dq, std::vector<int> &low, std::vector<int> &disc, std::vector<std::vector<int>> &bcc);
};
Graph::Graph(const std::vector<std::pair<int,int>> &ad, int nodes, int edges, int directed) : nodes(nodes), edges(edges), directed(directed) {
Ad.resize(nodes+1);
for(int i = 0; i<edges; ++i){
Ad[ad[i].first].push_back(ad[i].second);
if(directed == 0)
Ad[ad[i].second].push_back(ad[i].first);
}
}
void Graph::DFS(int node, std::vector<int> &vis){
vis[node] = 1;
for(int i = 0; i<Ad[node].size(); ++i)
if(vis[Ad[node][i]] == 0){
DFS(Ad[node][i], vis);
}
}
int Graph::getComponents() {
std::vector<int> vis;
int ct = 0;
vis.resize(nodes);
std::fill(vis.begin(), vis.end(), 0);
for(int i = 1;i <= nodes; ++i)
if(vis[i] == 0){
DFS(i, vis);
ct++;
}
return ct;
}
void Graph::BFS(int node, std::vector<int> &vis){
int parent, distance;
std::queue<int> Q;
Q.push(node);
vis[node] = 0;
while(!Q.empty()){
parent = Q.front();
Q.pop();
for(int i = 0; i<Ad[parent].size(); ++i)
if(vis[Ad[parent][i]] == -1){
Q.push(Ad[parent][i]);
vis[Ad[parent][i]] = vis[parent] + 1;
}
}
}
void Graph::pathTo(int node){
std::vector<int> vis;
vis.resize(nodes+1);
std::fill(vis.begin(), vis.end(), -1);
vis[node] = 0;
BFS(node, vis);
for(int i = 1; i<= nodes; ++i)
fout << vis[i]<< " ";
}
void Graph::topSortDFS(int node, std::vector<int> &vis, std::stack<int> &s){
vis[node] = 1;
for(int i = 0; i<Ad[node].size(); ++i)
if(vis[Ad[node][i]] == 0)
topSortDFS(Ad[node][i], vis, s);
s.push(node);
}
std::stack<int> Graph::topSort(){
std::vector<int> vis;
std::stack<int> s;
vis.resize(nodes+1);
std::fill(vis.begin(), vis.end(), 0);
for(int i = 1; i<=nodes; ++i)
if(!vis[i])
topSortDFS(i, vis, s);
return s;
}
void HavelHakimi(){
std::vector<int> v;
int n,x, val; // val - deleted value in havel hakimi
bool hh = true; //check if havel hakimi conditions are still met
fin >> n;
for(int i = 0; i<n; ++i){
fin >> x;
v.push_back(x);
}
while(true){
sort(v.begin(), v.end(), greater<>());
if(v[0] == 0)
break;
val = v[0];
v.erase(v.begin());
if(v.size() < val){
hh = false;
break;
}
for(int i = 0; i<val; ++i){
v[i]--;
if(v[i] < 0){
hh = false;
break;
}
}
}
if( hh == true )
std::cout << "Simple graph.";
else std::cout << "Not a simple graph.";
}
void Graph::dfsSCC(int node,int &idInc, std::vector<int> &id, std::vector<int> &low, std::vector<bool> &onStack, std::stack<int> &s, std::vector< std::vector<int>> &scc){
int nod;
s.push(node);
onStack[node] = true;
id[node] = low[node] = idInc++;
for(int i = 0; i<Ad[node].size(); ++i){
int next = Ad[node][i];
if(id[next] == 0)
dfsSCC(next, idInc, id, low, onStack, s, scc);
if(onStack[next] == true)
low[node] = min(low[node], low[next]);
}
if(id[node] == low[node]){
std::vector<int> comp; ///next component in scc vector
while(!s.empty()){
nod = s.top();
s.pop();
onStack[nod] = false;
comp.push_back(nod);
low[nod] = id[node];
if(nod == node)
break;
}
scc.push_back(comp);
}
}
std::vector< std::vector<int>> Graph::getSCC(){
int idInc = 1; //increment node id
std::vector<int> id(nodes+1);
std::vector<int> low(nodes+1);
std::vector<bool> onStack(nodes+1, 0);
std::vector< std::vector<int>> scc; //vector of components
std::stack<int> s;
for(int i = 1; i<=nodes; ++i)
id[i] = low[i] = 0;
for(int i = 1; i<=nodes; ++i)
if(id[i] == 0)
dfsSCC(i,idInc, id, low, onStack, s, scc);
return scc;
}
void Graph::printSCC(){
std::vector< std::vector<int>> scc;
scc = getSCC();
fout << scc.size() << "\n";
for(int i = 0; i<scc.size(); ++i){
for(int j = 0; j<scc[i].size(); ++j)
fout << scc[i][j] << " ";
fout << "\n";
}
}
void Graph::dfsBCC(int node, int parent, int &time, std::vector<int> &dq, std::vector<int> &low, std::vector<int> &disc, std::vector<std::vector<int>> &bcc){
int w;
disc[node] = low[node] = ++time;
for(int i = 0; i<Ad[node].size(); ++i){
w = Ad[node][i];
if(w == parent)
continue;
if(disc[w] != 0)
low[node] = min(low[node], disc[w]);
else{
dq.push_back(w);
dfsBCC(w, node, time, dq, low, disc, bcc);
low[node] = min(low[w], low[node]);
if(low[w] >= disc[node]){
dq.push_back(node);
std::vector<int> nextComp;
while(!dq.empty()){
int next = dq.back();
dq.pop_back();
nextComp.push_back(next);
if(next == w)
break;
}
bcc.push_back(nextComp);
}
}
}
}
void Graph::printBCC(){
int time = 0;
std::vector<std::vector<int>> bcc;
std::vector<int> dq; ///deque for components in next bcc
std::vector<int> low(nodes), disc(nodes);
dfsBCC(1,0,time, dq, low, disc, bcc);
fout << bcc.size() << "\n";
for(int i = 0; i<bcc.size(); ++i){
for(int j = 0; j<bcc[i].size(); ++j)
fout << bcc[i][j] << " ";
fout << "\n";
}
}
int main() {
std::vector<std::pair<int,int>> Ad;
std::stack<int> s;
int n,m,x,y;
fin >> n >> m;
for(int i = 0; i<m; ++i){
fin >> x >> y;
Ad.push_back({x,y});
}
Graph G(Ad,n ,m, 0);
G.printBCC();
return 0;
}