#include <vector>

template<typename T>
struct edge {
    std::size_t to; T cost;
    edge (std::size_t to, T cost = 1) : to(to), cost(cost) { }
    bool operator< (const edge &r) const { return (cost < r.cost); }
};

template<typename T>
using graph = std::vector<std::vector<edge<T>>>;

#include <stack>
#include <cstddef>
#include <functional>
#include <algorithm>

template<class T>
std::vector<std::vector<std::size_t>> strongly_connected_component (const graph<T> &g) {
	using std::size_t;
	size_t index = 0;
	std::vector<std::vector<size_t>> scc;
	std::vector<size_t> low(g.size()), order(g.size());
	std::stack<size_t> stack;
	std::vector<bool> instack(g.size(), false);
	std::function<void(size_t)> dfs = [&] (size_t v) {
		low[v] = order[v] = ++index;
		stack.push(v); instack[v] = true;
		for (const auto &e : g[v]) {
			if (order[e.to] == 0) {
				dfs(e.to);
				if (low[v] > low[e.to]) low[v] = low[e.to];
			} else if (instack[e.to] and low[v] > order[e.to]) {
				low[v] = order[e.to];
			}
		}
		if (low[v] == order[v]) {
			scc.push_back(std::vector<size_t>());
			while (true) {
				const size_t u = stack.top();
				stack.pop(); instack[u] = false;
				scc.back().push_back(u);
				if (v == u) break;
			}
		}
	};
	for (size_t v = 0; v < g.size(); v++) {
		if (order[v] == 0) dfs(v);
	}
	std::reverse(scc.begin(), scc.end());
	return scc;
}

#include <iostream>

using usize = std::size_t;

int main() {
	usize n, m;
	std::cin >> n >> m;
	graph<int> g(n);
	for (usize i = 0; i < m; i++) {
		usize a, b;
		std::cin >> a >> b;
		g[a].emplace_back(b);
	}
	
	auto scc = strongly_connected_component(g);
	std::cout << scc.size() << '\n';
	for (auto &v : scc) {
		std::cout << v.size();
		for (auto &e : v) std::cout << ' ' << e;
		std::cout << '\n';
	}
	
	return 0;
}