# TODO: メモリリーク確認
# TODO: __repr__ を書く

code_scc_graph = r"""
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include "structmember.h"

// 元のライブラリの private を剥がした

// >>> AtCoder >>>

#ifndef ATCODER_SCC_HPP
#define ATCODER_SCC_HPP 1

#include <algorithm>

#ifndef ATCODER_INTERNAL_SCC_HPP
#define ATCODER_INTERNAL_SCC_HPP 1

#include <algorithm>
#include <utility>
#include <vector>

namespace atcoder {
namespace internal {

template <class E> struct csr {
    std::vector<int> start;
    std::vector<E> elist;
    csr(int n, const std::vector<std::pair<int, E>>& edges)
        : start(n + 1), elist(edges.size()) {
        for (auto e : edges) {
            start[e.first + 1]++;
        }
        for (int i = 1; i <= n; i++) {
            start[i] += start[i - 1];
        }
        auto counter = start;
        for (auto e : edges) {
            elist[counter[e.first]++] = e.second;
        }
    }
};

// Reference:
// R. Tarjan,
// Depth-First Search and Linear Graph Algorithms
struct scc_graph {
  public:
    scc_graph(int n) : _n(n) {}

    int num_vertices() { return _n; }

    void add_edge(int from, int to) { edges.push_back({from, {to}}); }

    // @return pair of (# of scc, scc id)
    std::pair<int, std::vector<int>> scc_ids() {
        auto g = csr<edge>(_n, edges);
        int now_ord = 0, group_num = 0;
        std::vector<int> visited, low(_n), ord(_n, -1), ids(_n);
        visited.reserve(_n);
        auto dfs = [&](auto self, int v) -> void {
            low[v] = ord[v] = now_ord++;
            visited.push_back(v);
            for (int i = g.start[v]; i < g.start[v + 1]; i++) {
                auto to = g.elist[i].to;
                if (ord[to] == -1) {
                    self(self, to);
                    low[v] = std::min(low[v], low[to]);
                } else {
                    low[v] = std::min(low[v], ord[to]);
                }
            }
            if (low[v] == ord[v]) {
                while (true) {
                    int u = visited.back();
                    visited.pop_back();
                    ord[u] = _n;
                    ids[u] = group_num;
                    if (u == v) break;
                }
                group_num++;
            }
        };
        for (int i = 0; i < _n; i++) {
            if (ord[i] == -1) dfs(dfs, i);
        }
        for (auto& x : ids) {
            x = group_num - 1 - x;
        }
        return {group_num, ids};
    }

    std::vector<std::vector<int>> scc() {
        auto ids = scc_ids();
        int group_num = ids.first;
        std::vector<int> counts(group_num);
        for (auto x : ids.second) counts[x]++;
        std::vector<std::vector<int>> groups(ids.first);
        for (int i = 0; i < group_num; i++) {
            groups[i].reserve(counts[i]);
        }
        for (int i = 0; i < _n; i++) {
            groups[ids.second[i]].push_back(i);
        }
        return groups;
    }

  private:
    int _n;
    struct edge {
        int to;
    };
    std::vector<std::pair<int, edge>> edges;
};

}  // namespace internal

}  // namespace atcoder

#endif  // ATCODER_INTERNAL_SCC_HPP

#include <cassert>
#include <vector>

namespace atcoder {

struct scc_graph {
  public:
    scc_graph() : internal(0) {}
    scc_graph(int n) : internal(n) {}

    void add_edge(int from, int to) {
        int n = internal.num_vertices();
        assert(0 <= from && from < n);
        assert(0 <= to && to < n);
        internal.add_edge(from, to);
    }

    std::vector<std::vector<int>> scc() { return internal.scc(); }

//  private:
    internal::scc_graph internal;
};

}  // namespace atcoder

#endif  // ATCODER_SCC_HPP

// <<< AtCoder <<<

using namespace std;
using namespace atcoder;
#define PARSE_ARGS(types, ...) if(!PyArg_ParseTuple(args, types, __VA_ARGS__)) return NULL


struct SCCGraph{
    PyObject_HEAD
    scc_graph* graph;
    const int n() const { return graph->internal.num_vertices(); }
};


extern PyTypeObject SCCGraphType;


// >>> SCCGraph definition >>>

static void SCCGraph_dealloc(SCCGraph* self){
    delete self->graph;
    Py_TYPE(self)->tp_free((PyObject*)self);
}
static PyObject* SCCGraph_new(PyTypeObject* type, PyObject* args, PyObject* kwds){
    return type->tp_alloc(type, 0);
}
static int SCCGraph_init(SCCGraph* self, PyObject* args){
    long n;
    if(!PyArg_ParseTuple(args, "l", &n)) return -1;
    if(n < 0 || n > (long)1e8){
        PyErr_Format(PyExc_IndexError,
            "SCCGraph constructor constraint error (constraint: 0<=n<=1e8, got n=%d)", n);
        return -1;
    }
    self->graph = new scc_graph(n);
    return 0;
}
static PyObject* SCCGraph_add_edge(SCCGraph* self, PyObject* args){
    long from, to;
    PARSE_ARGS("ll", &from, &to);
    if(from < 0 || from >= self->n() || to < 0 || to >= self->n()){
        PyErr_Format(PyExc_IndexError,
            "SCCGraph add_ede index out of range (n=%d, from=%d, to=%d)", self->n(), from, to);
        return (PyObject*)NULL;
    }
    self->graph->add_edge(from, to);
    Py_RETURN_NONE;
}
static PyObject* SCCGraph_scc(SCCGraph* self, PyObject* args){
    const vector<vector<int>>& scc = self->graph->scc();
    PyObject* list = PyList_New(scc.size());
    for(int i = 0; i < scc.size(); i++){
        PyObject* lst = PyList_New(scc[i].size());
        for(int j = 0; j < scc[i].size(); j++){
            PyList_SET_ITEM(lst, j, Py_BuildValue("l", scc[i][j]));
        }
        PyList_SET_ITEM(list, i, lst);
    }
    return list;
}
/*
static PyObject* SCCGraph_repr(PyObject* self){
    PyObject* res = PyUnicode_FromFormat("SCCGraph()");
    return res;
}
*/
static PyMethodDef SCCGraph_methods[] = {
    {"add_edge", (PyCFunction)SCCGraph_add_edge, METH_VARARGS, "Add clause"},
    {"scc", (PyCFunction)SCCGraph_scc, METH_VARARGS, "Check if problem satisfiable"},
    {NULL}  /* Sentinel */
};
PyTypeObject SCCGraphType = {
    PyObject_HEAD_INIT(NULL)
    "acl_scc.SCCGraph",                 /*tp_name*/
    sizeof(SCCGraph),                   /*tp_basicsize*/
    0,                                  /*tp_itemsize*/
    (destructor)SCCGraph_dealloc,       /*tp_dealloc*/
    0,                                  /*tp_print*/
    0,                                  /*tp_getattr*/
    0,                                  /*tp_setattr*/
    0,                                  /*reserved*/
    0,//SCCGraph_repr,                    /*tp_repr*/
    0,                                  /*tp_as_number*/
    0,                                  /*tp_as_sequence*/
    0,                                  /*tp_as_mapping*/
    0,                                  /*tp_hash*/
    0,                                  /*tp_call*/
    0,                                  /*tp_str*/
    0,                                  /*tp_getattro*/
    0,                                  /*tp_setattro*/
    0,                                  /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
    0,                                  /*tp_doc*/
    0,                                  /*tp_traverse*/
    0,                                  /*tp_clear*/
    0,                                  /*tp_richcompare*/
    0,                                  /*tp_weaklistoffset*/
    0,                                  /*tp_iter*/
    0,                                  /*tp_iternext*/
    SCCGraph_methods,                   /*tp_methods*/
    0,                                  /*tp_members*/
    0,                                  /*tp_getset*/
    0,                                  /*tp_base*/
    0,                                  /*tp_dict*/
    0,                                  /*tp_descr_get*/
    0,                                  /*tp_descr_set*/
    0,                                  /*tp_dictoffset*/
    (initproc)SCCGraph_init,            /*tp_init*/
    0,                                  /*tp_alloc*/
    SCCGraph_new,                       /*tp_new*/
    0,                                  /*tp_free*/
    0,                                  /*tp_is_gc*/
    0,                                  /*tp_bases*/
    0,                                  /*tp_mro*/
    0,                                  /*tp_cache*/
    0,                                  /*tp_subclasses*/
    0,                                  /*tp_weaklist*/
    0,                                  /*tp_del*/
    0,                                  /*tp_version_tag*/
    0,                                  /*tp_finalize*/
};

// <<< SCCGraph definition <<<


static PyModuleDef acl_sccmodule = {
    PyModuleDef_HEAD_INIT,
    "acl_scc",
    NULL,
    -1,
};

PyMODINIT_FUNC PyInit_acl_scc(void)
{
    PyObject* m;
    if(PyType_Ready(&SCCGraphType) < 0) return NULL;

    m = PyModule_Create(&acl_sccmodule);
    if(m == NULL) return NULL;

    Py_INCREF(&SCCGraphType);
    if (PyModule_AddObject(m, "SCCGraph", (PyObject*)&SCCGraphType) < 0) {
        Py_DECREF(&SCCGraphType);
        Py_DECREF(m);
        return NULL;
    }
    
    return m;
}
"""
code_scc_graph_setup = r"""
from distutils.core import setup, Extension
module = Extension(
    "acl_scc",
    sources=["scc_graph.cpp"],
    extra_compile_args=["-O3", "-march=native", "-std=c++14"]
)
setup(
    name="acl_scc",
    version="0.0.1",
    description="wrapper for atcoder library scc",
    ext_modules=[module]
)
"""

import os
import sys

if sys.argv[-1] == "ONLINE_JUDGE" or os.getcwd() != "/imojudge/sandbox":
    with open("scc_graph.cpp", "w") as f:
        f.write(code_scc_graph)
    with open("scc_graph_setup.py", "w") as f:
        f.write(code_scc_graph_setup)
    os.system(f"{sys.executable} scc_graph_setup.py build_ext --inplace")

from acl_scc import SCCGraph


def main():
    N, M = map(int, sys.stdin.buffer.readline().split())
    m = map(int, sys.stdin.buffer.read().split())
    g = SCCGraph(N)
    for a, b in zip(m, m):
        g.add_edge(a, b)
    scc = g.scc()
    print(len(scc))
    for v in scc:
        print(len(v), " ".join(map(str, v)))

main()


Measured memory_bytes: 104424