#include <stack>
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
using namespace std;
typedef unsigned int uint;
class Node {
int id;
int discovery_time;
int lowlink;
public:
bool in_stack;
Node(int id) : id(id) { reset(); }
~Node() {}
int get_id() { return id; }
void set_time(int time) { discovery_time = time; }
int get_time() { return discovery_time; }
void set_lowlink(int x) { lowlink = x; }
int get_lowlink() { return lowlink; }
void reset() { discovery_time = UNSET; }
bool visited() { return !(discovery_time == UNSET); }
const static int UNSET = -1;
};
class Graph {
vector<Node *> nodes;
vector<vector<Node *> > edges;
int time;
stack<Node *> st;
vector<vector<Node *> > solution;
public:
Graph() {
reset();
fstream input("ctc.in", ios_base::in);
int nodes_no, edges_no;
input >> nodes_no >> edges_no;
nodes = vector<Node *>(nodes_no + 1, NULL);
edges = vector<vector<Node *> >(nodes_no + 1, vector<Node *>());
for(int i = 1; i <= nodes_no; i++) {
nodes.at(i) = new Node(i);
}
for(int i = 0; i < edges_no; i++) {
int n1, n2;
input >> n1 >> n2;
edges[n1].push_back(nodes[n2]);
}
input.close();
}
~Graph() {
for(uint i = 1; i < nodes.size(); i++)
delete nodes[i];
}
void reset() {
solution = vector<vector<Node *> >();
st = stack<Node *>();
time = 0;
for(uint i = 1; i < nodes.size(); i++)
nodes[i]->reset();
}
void print() {
for(uint i = 1; i < edges.size(); i++) {
cout << i << ": ";
for(uint j = 0; j < edges[i].size(); j++)
cout << edges[i][j]->get_id() << "--";
cout << "\n";
}
}
void ctc_tarjan() {
reset();
for(uint i = 1; i < nodes.size(); i++) {
if(!nodes[i]->visited())
tarjan(nodes[i]);
}
fstream output("ctc.out", ios_base::out);
output << solution.size() << "\n";
for(uint i = 0; i < solution.size(); i++) {
for(uint j = 0; j < solution[i].size(); j++)
output << solution[i][j]->get_id() << " ";
output << "\n";
}
output.close();
}
void tarjan(Node *node) {
// cout << "Visiting node: " << node->get_id() << " at time: " << time << "\n";
Node *neighbour;
node->set_time(time);
node->set_lowlink(time);
time++;
st.push(node);
node->in_stack = true;
for(uint i = 0; i < edges[node->get_id()].size(); i++) {
neighbour = edges[node->get_id()][i];
// cout << "-->Checking neighbour: " << neighbour->get_id() << " -->";
if(!neighbour->visited()) {
// cout << " visiting him \n";
tarjan(neighbour);
// cout << "[--] Came back to node: " << node->get_id() << " and neighbour: "
// << neighbour->get_id() << " lowlinks are: (" << node->get_lowlink()
// << ", " << neighbour->get_lowlink() << ")\n";
node->set_lowlink(min(node->get_lowlink(), neighbour->get_lowlink()));
}
else
if(neighbour->in_stack) {
// cout << " already visited with disc_time: " << neighbour->get_time();
node->set_lowlink(min(node->get_lowlink(), neighbour->get_time()));
// cout << " lowlink changed to: " << node->get_lowlink() << "\n";
}
}
if(node->get_lowlink() == node->get_time()) {
Node *n;
vector<Node *> sol;
do {
n = st.top();
st.pop();
n->in_stack = false;
sol.push_back(n);
}
while (node->get_id() != n->get_id());
solution.push_back(sol);
}
}
};
int main() {
Graph g;
g.ctc_tarjan();
}