#define _CRT_SECURE_NO_WARNINGS
#include <algorithm>
#include <vector>
#include <stack>
#include <unordered_map>
#define UInt32 unsigned
template <typename T>
class Graph {
protected:
std::unordered_map<T, UInt32> nodeMap;
std::unordered_map<UInt32, T> nodeInvMap;
std::vector<std::vector<UInt32>> adj;
public:
Graph() {}
Graph(UInt32 nodesCnt) : Graph() { Create(nodesCnt); }
Graph(const Graph<T> &other) : nodeMap(other.nodeMap), adj(other.adj) {}
virtual ~Graph() {}
public:
inline UInt32 Size() const { return nodeMap.size(); }
inline bool addNode(T node) {
UInt32 size = Size();
nodeMap[node] = size;
nodeInvMap[size] = node;
return true;
}
inline bool addEdge(T src, T dst) {
UInt32 srcIndex = src;
UInt32 dstIndex = dst;
adj[srcIndex].push_back(dstIndex);
return true;
}
bool Create(UInt32 nodesCnt) {
Clear();
adj.resize(nodesCnt);
for (UInt32 tr = 0; tr < nodesCnt; ++tr) addNode(tr);
return true;
}
bool Clear() {
adj.clear();
return true;
}
public:
bool ConnectedComponents(std::vector<std::vector<UInt32>> &components) {
std::vector<UInt32> parent;
UInt32 parentFrom, parentTo, index;
std::unordered_map<UInt32, UInt32> componentIndex;
for (UInt32 i = 0; i<Size(); ++i) {
parent.push_back(i);
}
for (UInt32 i = 0; i<Size(); ++i) {
for (UInt32 j = 0; j<adj[i].size(); ++j) {
parentFrom = i;
parentTo = adj[i][j];
while (parent[parentFrom] != parentFrom) {
parentFrom = (parent[parentFrom] = parent[parent[parentFrom]]);
}
while (parent[parentTo] != parentTo) {
parentTo = (parent[parentTo] = parent[parent[parentTo]]);
}
if (parentFrom != parentTo) {
parent[parentFrom] = parentTo;
}
}
}
for (UInt32 i = 0; i<Size(); ++i) {
parentFrom = parent[i];
while (parent[parentFrom] != parentFrom) {
parentFrom = (parent[parentFrom] = parent[parent[parentFrom]]);
}
if (!componentIndex.count(parentFrom)) {
UInt32 index = componentIndex.size();
componentIndex[parentFrom] = index;
components.push_back(std::vector<UInt32>());
}
index = componentIndex[parentFrom];
components[index].push_back(i);
}
return true;
}
bool StrongComponents(std::vector<std::vector<UInt32>> &components) {
UInt32 tr, size = Size();
UInt32 src, dst;
std::vector<bool> onStack(size);
std::vector<UInt32> disc(size), low(size); // discovery, lowestAccessibleDisc
std::stack<std::pair<UInt32, UInt32>> bk;
std::stack<UInt32> st;
for (tr = 0; tr < size; ++tr) {
if (!disc[tr]) {
UInt32 time = 0;
disc[tr] = low[tr] = ++time;
onStack[tr] = true;
bk.push(std::make_pair(tr, 0));
st.push(tr);
while (bk.size()) {
src = bk.top().first;
if (bk.top().second < adj[src].size()) {
dst = adj[src][bk.top().second++];
if (!disc[dst]) {
low[dst] = disc[dst] = ++time;
onStack[dst] = true;
bk.push(std::make_pair(dst, 0));
st.push(dst);
}
else if (onStack[dst]) {
low[src] = std::min(low[src], low[dst]);
}
}
else {
if (disc[src] == low[src]) {
components.push_back(std::vector<UInt32>());
UInt32 node;
do {
components.back().push_back(nodeInvMap[node = st.top()]);
onStack[node] = false;
st.pop();
} while (node != src);
}
bk.pop();
if (bk.size()) {
dst = src;
src = bk.top().first;
low[src] = std::min(low[src], low[dst]);
}
}
}
}
}
return true;
}
};
template <typename T, typename I>
class Graph<std::pair<T, I>> {
protected:
std::unordered_map<T, UInt32> nodeMap;
std::unordered_map<UInt32, T> nodeInvMap;
std::vector<std::vector<std::pair<UInt32, I>>> adj;
public:
Graph() {}
Graph(UInt32 nodesCnt) : Graph() { Create(nodesCnt); }
Graph(const Graph<T> &other) : nodeMap(other.nodeMap), adj(other.edges) {}
virtual ~Graph() {}
public:
inline UInt32 Size() const { return nodeMap.size(); }
inline bool addNode(T node) {
UInt32 size = Size();
nodeMap[node] = size;
nodeInvMap[size] = node;
return true;
}
inline bool addEdge(T src, T dst) {
UInt32 srcIndex = src;
UInt32 dstIndex = dst;
adj[srcIndex].push_back(dstIndex);
return true;
}
bool Create(UInt32 nodesCnt) {
Clear();
adj.resize(nodesCnt);
for (UInt32 tr = 0; tr < nodesCnt; ++tr) addNode(tr);
return true;
}
bool Clear() {
adj.clear();
return true;
}
public:
bool ConnectedComponents(std::vector<std::vector<UInt32>> &components) {
std::vector<UInt32> parent;
UInt32 parentFrom, parentTo, index;
std::unordered_map<UInt32, UInt32> componentIndex;
for (UInt32 i = 0; i<Size(); ++i) {
parent.push_back(i);
}
for (UInt32 i = 0; i<Size(); ++i) {
for (UInt32 j = 0; j<adj[i].size(); ++j) {
parentFrom = i;
parentTo = adj[i][j].first;
while (parent[parentFrom] != parentFrom) {
parentFrom = (parent[parentFrom] = parent[parent[parentFrom]]);
}
while (parent[parentTo] != parentTo) {
parentTo = (parent[parentTo] = parent[parent[parentTo]]);
}
if (parentFrom != parentTo) {
parent[parentFrom] = parentTo;
}
}
}
for (UInt32 i = 0; i<Size(); ++i) {
parentFrom = parent[i];
while (parent[parentFrom] != parentFrom) {
parentFrom = (parent[parentFrom] = parent[parent[parentFrom]]);
}
if (!componentIndex.count(parentFrom)) {
UInt32 index = componentIndex.size();
componentIndex[parentFrom] = index;
components.push_back(std::vector<UInt32>());
}
index = componentIndex[parentFrom];
components[index].push_back(i);
}
return true;
}
bool StrongComponents(std::vector<std::vector<UInt32>> &components) {
UInt32 tr, size = Size();
UInt32 src, dst;
std::vector<bool> onStack(size);
std::vector<UInt32> disc(size), low(size); // discovery, lowestAccessibleDisc
std::stack<std::pair<UInt32, UInt32>> bk;
std::stack<UInt32> st;
for (tr = 0; tr < size; ++tr) {
if (!disc[tr]) {
UInt32 time = 0;
disc[tr] = low[tr] = ++time;
onStack[tr] = true;
bk.push(std::make_pair(tr, 0));
st.push(tr);
while (bk.size()) {
src = bk.top().first;
if (bk.top().second < adj[src].size()) {
dst = adj[src][bk.top().second++].first;
if (!disc[dst]) {
low[dst] = disc[dst] = ++time;
onStack[dst] = true;
bk.push(std::make_pair(dst, 0));
st.push(dst);
}
else if (onStack[dst]) {
low[src] = std::min(low[src], disc[dst]);
}
}
else {
if (disc[src] == low[src]) {
components.push_back(std::vector<UInt32>());
UInt32 node;
do {
components.back().push_back(nodeInvMap[node = st.top()]);
onStack[node] = false;
st.pop();
} while (node != src);
}
bk.pop();
if (bk.size()) {
dst = src;
src = bk.top().first;
low[src] = std::min(low[src], low[dst]);
}
}
}
}
}
return true;
}
};
int main(int argc, char *argv[])
{
Graph<int> g;
int n = 0, m = 0;
std::vector<std::vector<unsigned>> components;
freopen("ctc.in", "r", stdin);
freopen("ctc.out", "w", stdout);
scanf("%d %d", &n, &m);
g.Create(n);
for (int i = 0; i<m; ++i) {
int x = 0, y = 0;
scanf("%d %d", &x, &y);
g.addEdge(x-1, y-1);
}
g.StrongComponents(components);
printf("%d\n", components.size());
for (unsigned i = 0; i<components.size(); ++i) {
for (unsigned j = 0; j<components[i].size(); ++j) {
printf("%d ", components[i][j] + 1);
}
puts("");
}
return 0;
}