<?php

/**
 * Class SCC
 * 有向グラフを強連結成分分解します。
 * TwoSatでも使用しているため、書き換える際は注意。
 * ref. AtCoder Library
 */
class SCC
{

    private int $n;
    private array $edges;
    private array $start;
    private array $elist;

    /**
     * MaxFlow constructor.
     * n 頂点 0 辺の有向グラフを作る。
     * 計算量 O(n)
     * @param int $n 0 ≤ n ≤ 10^8
     */
    function __construct(int $n)
    {
        $this->n = $n;
    }

    /**
     * 頂点fromから頂点toへ有向辺を足す。
     * 計算量 ならしO(1)
     * @param int $from 0 ≤ from < n
     * @param int $to 0 ≤ to < n
     */
    public function add_edge(int $from, int $to): void
    {
        assert(0 <= $from && $from < $this->n);
        assert(0 <= $to && $to < $this->n);
        $this->edges[] = [$from, $to];
    }

    public function csr(): void
    {
        $this->start = $this->elist =  array_fill(0, $this->n+1, 0);
        foreach($this->edges as $e){
            $this->start[$e[0] + 1]++;
        }
        for($i=1; $i<=$this->n; $i++){
            $this->start[$i] += $this->start[$i-1];
        }
        $counter = $this->start;
        foreach($this->edges as $e){
            $this->elist[$counter[$e[0]]++] = $e[1];
        }
    }

    private function scc_ids(): array
    {
        $this->csr();
        $now_ord = $group_num = 0;
        $visited = new SplDoublyLinkedList();
        $visited->setIteratorMode(SplDoublyLinkedList::IT_MODE_DELETE | SplDoublyLinkedList::IT_MODE_LIFO);
        $low = $ids = array_fill(0, $this->n, 0);
        $ord = array_fill(0, $this->n, -1);
        $dfs = function($v) use(&$now_ord, &$visited, &$ord, &$low, &$dfs, &$ids, &$group_num){
            $low[$v] = $ord[$v] = $now_ord++;
            $visited->push($v);
            for($i=$this->start[$v]; $i < $this->start[$v +1]; $i++) {
                $to = $this->elist[$i];
                if ($ord[$to] === -1) {
                    $dfs($to);
                    $low[$v] = min($low[$v], $low[$to]);
                } else {
                    $low[$v] = min($low[$v], $ord[$to]);
                }
            }
            if($low[$v] === $ord[$v]){
                while(true){
                    $u = $visited->pop();
                    $ord[$u] = $this->n;
                    $ids[$u] = $group_num;
                    if($u === $v){
                        break;
                    }
                }
                $group_num++;
            }
        };
        for($i=0;$i<$this->n; $i++){
            if($ord[$i] === -1){
                $dfs($i);
            }
        }
        foreach($ids as &$x){
            $x = $group_num - 1 - $x;
        }
        return [$group_num, $ids];

    }

    /**
     * 以下の条件を満たすような「頂点のリスト」のリストを返します。
     * ・全ての頂点がちょうど1つずつ、どれかのリストに含まれます。
     * ・内側のリストと強連結成分が一対一に対応します。リスト内での頂点の順序は未定義です。
     * ・リストはトポロジカルソートされています。異なる強連結成分の頂点 u, vu,v について、uu から vv に到達できる時、uu の属するリストは vv の属するリストよりも前です。
     * 計算量　追加した辺の本数をmとして
     * O(n+m)
     * @return array
     */
    public function scc():array
    {
        $ids = $this->scc_ids();
        $group_num = $ids[0];
        $counts =  array_fill(0,$group_num, 0);
        $groups = array_fill(0,$group_num, []);;
        foreach($ids[1] as $x){
            $counts[$x]++;
        }
        for($i=0;$i<$this->n;$i++){
            $groups[$ids[1][$i]][] = $i;
        }
        return $groups;
    }
}

[$N, $M] = fscanf(STDIN, "%d%d");
$g = new SCC($N);
for($i=0;$i<$M;$i++){
    [$U, $V] = fscanf(STDIN, "%d%d");
    $g->add_edge($U, $V);
}

$scc = $g->scc();

echo count($scc).PHP_EOL;
foreach($scc as $row){
    echo count($row)." ".implode(" ",$row).PHP_EOL;
}


Measured memory_bytes: 525692