package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
var sc = bufio.NewScanner(os.Stdin)
func Scan() string {
sc.Scan()
return sc.Text()
}
func rScan() []rune {
return []rune(Scan())
}
func iScan() int {
n, _ := strconv.Atoi(Scan())
return n
}
func fScan() float64 {
n, _ := strconv.ParseFloat(Scan(), 64)
return n
}
func stringToInt(s string) int {
n, _ := strconv.Atoi(s)
return n
}
func SScan(n int) []string {
a := make([]string, n)
for i := 0; i < n; i++ {
a[i] = Scan()
}
return a
}
func iSScan(n int) []int {
a := make([]int, n)
for i := 0; i < n; i++ {
a[i] = iScan()
}
return a
}
func abs(x int) int {
if x < 0 {
x = -x
}
return x
}
func mod(x, d int) int {
x %= d
if x < 0 {
x += d
}
return x
}
func larger(a, b int) int {
if a < b {
return b
} else {
return a
}
}
func smaller(a, b int) int {
if a > b {
return b
} else {
return a
}
}
func max(a []int) int {
x := a[0]
for i := 0; i < len(a); i++ {
if x < a[i] {
x = a[i]
}
}
return x
}
func min(a []int) int {
x := a[0]
for i := 0; i < len(a); i++ {
if x > a[i] {
x = a[i]
}
}
return x
}
func sum(a []int) int {
x := 0
for _, v := range a {
x += v
}
return x
}
func fSum(a []float64) float64 {
x := 0.
for _, v := range a {
x += v
}
return x
}
func bPrint(f bool, x string, y string) {
if f {
fmt.Println(x)
} else {
fmt.Println(y)
}
}
func iSSPrint(x []int) {
fmt.Println(strings.Trim(fmt.Sprint(x), "[]"))
}
var lp1 int = 1000000007
var lp2 int = 998244353
func main() {
buf := make([]byte, 0)
sc.Buffer(buf, lp1)
sc.Split(bufio.ScanWords)
n := iScan()
m := iScan()
s := newSccGraph(n)
for i := 0; i < m; i++ {
s.AddEdge(iScan(), iScan())
}
ans := s.Scc()
fmt.Println(len(ans))
for _, v := range ans {
fmt.Print(len(v))
fmt.Print(" ")
iSSPrint(v)
}
}
type SccGraph struct {
n int
edges [][2]int
}
type Csr struct {
start []int
elist []int
}
func newSccGraph(n int) *SccGraph {
scc := new(SccGraph)
scc.n = n
return scc
}
func (scc *SccGraph) NumVertices() int {
return scc.n
}
func (scc *SccGraph) AddEdge(from int, to int) {
scc.edges = append(scc.edges, [2]int{from, to})
}
func (c *Csr) csr(n int, edges [][2]int) {
c.start = make([]int, n+1)
c.elist = make([]int, len(edges))
for _, e := range edges {
c.start[e[0]+1]++
}
for i := 1; i <= n; i++ {
c.start[i] += c.start[i-1]
}
counter := make([]int, n+1)
copy(counter, c.start)
for _, e := range edges {
c.elist[counter[e[0]]] = e[1]
counter[e[0]]++
}
}
func (scc *SccGraph) SccIds() (int, []int) {
g := new(Csr)
g.csr(scc.n, scc.edges)
nowOrd, groupNum := 0, 0
visited, low := make([]int, 0, scc.n), make([]int, scc.n)
ord, ids := make([]int, scc.n), make([]int, scc.n)
for i := 0; i < scc.n; i++ {
ord[i] = -1
}
var dfs func(v int)
dfs = func(v int) {
low[v], ord[v] = nowOrd, nowOrd
nowOrd++
visited = append(visited, v)
for i := g.start[v]; i < g.start[v+1]; i++ {
to := g.elist[i]
if ord[to] == -1 {
dfs(to)
low[v] = scc.min(low[v], low[to])
} else {
low[v] = scc.min(low[v], ord[to])
}
}
if low[v] == ord[v] {
for {
u := visited[len(visited)-1]
visited = visited[:len(visited)-1]
ord[u] = scc.n
ids[u] = groupNum
if u == v {
break
}
}
groupNum++
}
}
for i := 0; i < scc.n; i++ {
if ord[i] == -1 {
dfs(i)
}
}
for i := 0; i < len(ids); i++ {
ids[i] = groupNum - 1 - ids[i]
}
return groupNum, ids
}
func (scc *SccGraph) min(x, y int) int {
if x < y {
return x
} else {
return y
}
}
func (scc *SccGraph) Scc() [][]int {
groupNum, ids := scc.SccIds()
counts := make([]int, groupNum)
for _, x := range ids {
counts[x]++
}
groups := make([][]int, groupNum)
for i := 0; i < groupNum; i++ {
groups[i] = make([]int, 0, counts[i])
}
for i := 0; i < scc.n; i++ {
groups[ids[i]] = append(groups[ids[i]], i)
}
return groups
}