#include <bits/stdc++.h>
using namespace std;
ifstream f("ctc.in");
ofstream g("ctc.out");
const int MaxN = 100005;
int n, m;
int onst[MaxN], low[MaxN], val[MaxN], unde[MaxN], poz[MaxN], nr, tata[MaxN], aint[4 * MaxN], bef[MaxN], ans, d[MaxN];
bitset<MaxN> viz;
vector<int> gr[MaxN], tati[MaxN];
stack<int> st;
vector<vector<int> > comps;
void Ctc(int node) {
viz[node] = 1;
st.push(node);
onst[node] = st.size();
low[node] = onst[node];
for (auto son: gr[node]) {
if (!viz[son]) {
Ctc(son);
low[node] = min(low[node], low[son]);
}
else if (onst[son]) low[node] = min(low[node], onst[son]);
}
if (low[node] == onst[node]) {
vector<int> v;
while (st.top() != node) {
v.push_back(st.top());
onst[st.top()] = 0;
st.pop();
}
st.pop();
v.push_back(node);
onst[node] = 0;
sort(v.begin(), v.end());
for (auto x: v) unde[x] = v[0];
comps.push_back(v);
}
}
void Sortare(int node) {
viz[node] = 1;
for (auto son: gr[node]) {
if (!viz[son]) Sortare(son);
}
poz[node] = ++nr;
}
void Update(int node, int l, int r, int poz, int val) {
if (l == r) {
aint[node] = val;
return;
}
int mid = (l + r) / 2;
if (poz <= mid) Update(2 * node, l, mid, poz, val);
else Update(2 * node + 1, mid + 1, r, poz, val);
aint[node] = max(aint[2 * node], aint[2 * node + 1]);
}
int Query(int node, int l, int r, int ql, int qr) {
if (l >= ql && r <= qr) return aint[node];
int mid = (l + r) / 2;
int ret = 0;
if (ql <= mid) ret = max(ret, Query(2 * node, l, mid, ql, qr));
if (qr > mid) ret = max(ret, Query(2 * node + 1, mid + 1, r, ql, qr));
return ret;
}
void Dfs(int node) {
viz[node] = 1;
bef[node] = Query(1, 1, MaxN, val[node], val[node]);
if (val[node] > 1) d[node] = Query(1, 1, MaxN, 1, val[node] - 1) + 1;
else d[node] = 1;
ans = max(ans, d[node]);
if (bef[node] < d[node]) Update(1, 1, MaxN, val[node], d[node]);
for (auto son: gr[node])
if (!viz[son]) Dfs(son);
Update(1, 1, MaxN, val[node], bef[node]);
}
int main()
{
f >> n >> m;
for (int i = 1; i <= n; ++i) val[i] = 1;
for (int i = 1; i <= m; ++i) {
int x, y;
f >> x >> y;
gr[x].push_back(y);
}
Ctc(1);
g << comps.size() << '\n';
for (auto v: comps) {
for (auto x: v) g << x << ' ';
g << '\n';
}
viz.reset();
for (auto v: comps) {
int y = v.back();
vector<int> my;
for (auto node: v) {
for (auto son: gr[node]) {
if (unde[son] != unde[node]) my.push_back(unde[son]);
}
gr[node].clear();
}
gr[y].swap(my);
for (int i = 0; i < v.size() - 1; ++i) gr[v[i]].push_back(v[i + 1]);
}
for (int i = 1; i <= n; ++i) {
for (auto x: gr[i]) tati[x].push_back(i);
}
for (int i = 1; i <= n; ++i) if (!tati[i].size()) {
Sortare(i);
break;
}
for (int i = 1; i <= n; ++i) {
int pozmin = 1000000;
for (auto t: tati[i]) if (poz[t] < pozmin) tata[i] = t, pozmin = poz[t];
gr[i].clear();
}
for (int i = 1; i <= n; ++i) gr[tata[i]].push_back(i);
viz.reset();
for (int i = 1; i <= n; ++i) if (!tata[i]) Dfs(i);
//g << ans << '\n';
return 0;
}