#include <vector>
#include <iostream>
#include <numeric>
#include <algorithm>
#include <stack>
using namespace std;

/*
 * @title StronglyConnectedComponents
 */
class StronglyConnectedComponents2{
	int num,is_2sat,half,max_id;
	vector<vector<int>> edge,redge;
	vector<int> label,visited,order;
	inline void dfs(int curr){
		visited[curr] = 1;
		for(int next:edge[curr]) if(!visited[next]) dfs(next);
		order.push_back(curr);
	}
	inline void rdfs(int curr,int id){
		visited[curr] = 1;
		label[curr] = id;
		for(int next:redge[curr]) if(!visited[next]) rdfs(next,id);
	}
	inline int rev(int i) { return i < half ? i + half : i - half; }
public:
	StronglyConnectedComponents2(const int n, bool is_2sat=0):num(n),max_id(0),is_2sat(is_2sat){
		if(is_2sat) num*=2;
		edge.resize(num);
		redge.resize(num);
		label.resize(num);
		visited.resize(num);
		half=num/2;
	}
	inline int operator[](int idx) {
		return label[idx];
	}
	inline void make_edge(const int from,const int to) {
		edge[from].push_back(to);
		redge[to].push_back(from);
	}
    //xがflg_xならばyがflg_y
	inline void make_condition(int x, bool flg_x, int y, bool flg_y) {
		if (!flg_x) x = rev(x);
		if (!flg_y) y = rev(y);
		make_edge(x, y);
		make_edge(rev(y), rev(x));
	}
    //is_2sat=1のときに、2satを満たすかを返却する
	inline bool solve(void) {
		for(int& e:visited) e = 0;
		for(int i = 0; i < num; ++i) if(!visited[i]) dfs(i);
		for(int& e:visited) e = 0;
		reverse(order.begin(),order.end());
		for(int i:order) if(!visited[i]) rdfs(i,max_id++);
		if(!is_2sat) return true;
		for (int i = 0; i < num; ++i) if (label[i] == label[rev(i)]) return false;
		return true;
	}
    vector<vector<int>> topological_sort(void) {
        vector<vector<int>> ret(max_id);
        for(int i=0;i<num;++i) ret[label[i]].push_back(i);
        return ret;
    }
	int is_true(int i) {
		return label[i] > label[rev(i)];
	}
	void print(void) {
		for(auto id:label) cout << id << " ";
		cout << endl;
	}
};



/*
 * @title StronglyConnectedComponents
 */
class StronglyConnectedComponents{
public:
	int num,is_2sat,half,max_id,cnt;
	vector<vector<int>> edge;
	vector<int> label,order,low;
    stack<size_t> st;
	inline int rev(int i) { return i < half ? i + half : i - half; }
    void dfs(int from=0) {
        low[from]=order[from]=cnt++;
        st.push(from);
        for(int& to:edge[from]) {
            if(order[to]==-1) {
                dfs(to);
                low[from]=min(low[from],low[to]);
            }
            else {
                low[from]=min(low[from],order[to]);
            }
        }
        if (low[from] == order[from]) {
            while(st.size()) {
                int u = st.top();st.pop();
                order[u] = num;
                label[u] = max_id;
                if (u == from) break;
            }
            max_id++;
        }
    }
	StronglyConnectedComponents(const int n, bool is_2sat=0):num(n),max_id(0),cnt(0),is_2sat(is_2sat){
		if(is_2sat) num*=2;
		edge.resize(num);
		label.resize(num);
        order.resize(num,-1);
        low.resize(num);
		half=num/2;
	}
	inline int operator[](int idx) {
		return label[idx];
	}
	inline void make_edge(const int from,const int to) {
		edge[from].push_back(to);
	}
    //xがflg_xならばyがflg_y
	inline void make_condition(int x, bool flg_x, int y, bool flg_y) {
		if (!flg_x) x = rev(x);
		if (!flg_y) y = rev(y);
		make_edge(x, y);
		make_edge(rev(y), rev(x));
	}
    //is_2sat=1のときに、2satを満たすかを返却する
	inline bool solve(void) {
        //
        //labelを作る
        for (int i = 0; i < num; i++) if (order[i] == -1) dfs(i);
        //
		if(!is_2sat) return true;
		for (int i = 0; i < num; ++i) if (label[i] == label[rev(i)]) return false;
		return true;
	}
    vector<vector<int>> topological_sort(void) {
        vector<vector<int>> ret(max_id);
        for(int i=0;i<num;++i) ret[max_id-1-label[i]].push_back(i);
        return ret;
    }
	int is_true(int i) {
		return label[i] > label[rev(i)];
	}
	void print(void) {
		for(auto id:label) cout << id << " ";
		cout << endl;
	}
};


int main(){
    cin.tie(0);ios::sync_with_stdio(false);
    int N,M; cin >> N >> M;
    StronglyConnectedComponents scc(N);
    while(M--) {
        int u,v; cin >> u >> v;
        scc.make_edge(u,v);
    }
    scc.solve();
    // for(auto& e:scc.label) cout << e << " "; cout << endl;
    // for(auto& e:scc.order) cout << e << " "; cout << endl;
    auto vv=scc.topological_sort();
    cout << vv.size() << "\n";
    for(auto& v:vv) {
        cout << v.size();
        for(auto& e:v) cout << " " << e;
        cout << "\n";
    }
    return 0;
}


Measured memory_bytes: 59808