#-------最強ライブラリSCC(Python) ver25252------

class scc_graph:

  # n 頂点数

  def __init__(s, n): 

    s._n = n

    s.g = {}

    s.rg = {}

  def num_vertices(s): return s._n

  # 辺を追加 frm 矢元 to 矢先

  # O(1)

  def add_edge(s, frm, to): 

    if frm in s.g: s.g[frm].append(to)

    else: s.g[frm] = [to]

    if to in s.rg: s.rg[to].append(frm)

    else: s.rg[to] = [frm]



  # グループの個数と各頂点のグループidを返す

  def scc_ids(s):

    def dfs(v):

      stack = [v]

      while stack:

        t = stack[-1]

        vis[t] = True

        if t not in s.g:

          vs.append(stack.pop())

          continue

        for i in s.g[t]:

          if not vis[i]:

            stack.append(i)

            break

        else:

          vs.append(stack.pop())



    def rdfs(v, n):

      stack = [v]

      vis[v] = True

      ids[v] = n

      while stack:

        t = stack.pop()

        vis[t] = True

        if t not in s.rg: continue

        for i in s.rg[t]:

          if not vis[i]:

            ids[i] = n

            stack.append(i)



    vis = [False] * s._n 

    vs = []

    ids = [-1] * s._n

    for i in range(s._n):

      if not vis[i]:

        dfs(i)

    group_num = 0

    vis = [False] * s._n 

    for i in vs[::-1]:

      if not vis[i]:

        rdfs(i, group_num)

        group_num += 1

    return group_num, ids 



  # 強連結成分となっている頂点のリストのリスト トポロジカルソート済み

  # O(n + m)

  def scc(s):

    ids = s.scc_ids()

    group_num = ids[0]

    counts = [0] * group_num

    for x in ids[1]: counts[x] += 1

    groups = [[] for _ in range(group_num)]

    for i in range(s._n):

      groups[ids[1][i]].append(i)

    return groups



#-------最強ライブラリここまで------



import sys

def main():

  input = sys.stdin.readline



  n, m = list(map(int, input().split()))

  ab = [list(map(int, input().split())) for _ in range(m)]



  g = scc_graph(n)



  for i in range(m):

    u, v = ab[i]

    g.add_edge(u, v)



  scc = g.scc()



  print(len(scc))



  for v in scc:

    print(len(v), end = " ")

    for x in v:

      print(x, end = " ")

    print("")



main()

#-------最強ライブラリSCC(Python) ver25252------

import sys

sys.setrecursionlimit(1000000)



class scc_graph:

  # n 頂点数

  def __init__(s, n): 

    s._n = n

    s.g = {}

  def num_vertices(s): return s._n

  # 辺を追加 frm 矢元 to 矢先

  # O(1)

  def add_edge(s, frm, to): 

    if frm in s.g: s.g[frm].append(to)

    else: s.g[frm] = [to]



  # グループの個数と各頂点のグループidを返す

  def scc_ids(s):

    now_ord = group_num = 0

    visited = []

    low = [0] * s._n

    ord = [-1] * s._n

    ids = [0] * s._n

    # 再帰関数 

    def dfs(self, v, now_ord, group_num):

      low[v] = ord[v] = now_ord

      now_ord += 1

      visited.append(v)

      if v in s.g:

        for to in s.g[v]:

          if ord[to] == -1:

            now_ord, group_num = self(self, to, now_ord, group_num)

            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] = s._n

          ids[u] = group_num

          if u == v: break

        group_num += 1

      return now_ord, group_num



    for i in range(s._n):

      if ord[i] == -1: now_ord, group_num = dfs(dfs, i, now_ord, group_num)

    for i in range(s._n):

      ids[i] = group_num - 1 - ids[i]

    return [group_num, ids]



  # 強連結成分となっている頂点のリストのリスト トポロジカルソート済み

  # O(n + m)

  def scc(s):

    ids = s.scc_ids()

    group_num = ids[0]

    counts = [0] * group_num

    for x in ids[1]: counts[x] += 1

    groups = [[] for _ in range(group_num)]

    for i in range(s._n):

      groups[ids[1][i]].append(i)

    return groups



  class edge:

    def __init__(s, frm, to):

      s.frm = frm

      s.to = to





#-------最強ライブラリここまで------



def main():

  input = sys.stdin.readline



  n, m = list(map(int, input().split()))

  ab = [list(map(int, input().split())) for _ in range(m)]



  g = scc_graph(n)



  for i in range(m):

    u, v = ab[i]

    g.add_edge(u, v)



  scc = g.scc()



  print(len(scc))



  for v in scc:

    print(len(v), end = " ")

    for x in v:

      print(x, end = " ")

    print("")



main()

# -------最強ライブラリSCC(Python) ver25252------
class scc_graph:
    # n 頂点数
    def __init__(s, n):
        s._n = n
        s.g = {}
        s.rg = {}

    def num_vertices(s):
        return s._n

    # 辺を追加 frm 矢元 to 矢先
    # O(1)
    def add_edge(s, frm, to):
        if frm in s.g:
            s.g[frm].append(to)
        else:
            s.g[frm] = [to]
        if to in s.rg:
            s.rg[to].append(frm)
        else:
            s.rg[to] = [frm]

    # グループの個数と各頂点のグループidを返す
    def scc_ids(s):
        def dfs(v):
            stack = [v]
            while stack:
                t = stack[-1]
                vis[t] = True
                if t not in s.g:
                    vs.append(stack.pop())
                    continue
                for i in s.g[t]:
                    if not vis[i]:
                        stack.append(i)
                        break
                else:
                    vs.append(stack.pop())

        def rdfs(v, n):
            stack = [v]
            vis[v] = True
            ids[v] = n
            while stack:
                t = stack.pop()
                vis[t] = True
                if t not in s.rg:
                    continue
                for i in s.rg[t]:
                    if not vis[i]:
                        ids[i] = n
                        stack.append(i)

        vis = [False] * s._n
        vs = []
        ids = [-1] * s._n
        for i in range(s._n):
            if not vis[i]:
                dfs(i)
        group_num = 0
        vis = [False] * s._n
        for i in vs[::-1]:
            if not vis[i]:
                rdfs(i, group_num)
                group_num += 1
        return group_num, ids

    # 強連結成分となっている頂点のリストのリスト トポロジカルソート済み
    # O(n + m)
    def scc(s):
        ids = s.scc_ids()
        group_num = ids[0]
        counts = [0] * group_num
        for x in ids[1]:
            counts[x] += 1
        groups = [[] for _ in range(group_num)]
        for i in range(s._n):
            groups[ids[1][i]].append(i)
        return groups


# -------最強ライブラリここまで------
import sys


def main():
    input = sys.stdin.readline
    n, m = list(map(int, input().split()))
    ab = [list(map(int, input().split())) for _ in range(m)]
    g = scc_graph(n)
    for i in range(m):
        u, v = ab[i]
        g.add_edge(u, v)
    scc = g.scc()
    print(len(scc))
    for v in scc:
        print(len(v), end=" ")
        for x in v:
            print(x, end=" ")
        print("")


main()

# -------最強ライブラリSCC(Python) ver25252------
import sys

sys.setrecursionlimit(1000000)


class scc_graph:
    # n 頂点数
    def __init__(s, n):
        s._n = n
        s.g = {}

    def num_vertices(s):
        return s._n

    # 辺を追加 frm 矢元 to 矢先
    # O(1)
    def add_edge(s, frm, to):
        if frm in s.g:
            s.g[frm].append(to)
        else:
            s.g[frm] = [to]

    # グループの個数と各頂点のグループidを返す
    def scc_ids(s):
        now_ord = group_num = 0
        visited = []
        low = [0] * s._n
        ord = [-1] * s._n
        ids = [0] * s._n
        # 再帰関数
        def dfs(self, v, now_ord, group_num):
            low[v] = ord[v] = now_ord
            now_ord += 1
            visited.append(v)
            if v in s.g:
                for to in s.g[v]:
                    if ord[to] == -1:
                        now_ord, group_num = self(self, to, now_ord, group_num)
                        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] = s._n
                    ids[u] = group_num
                    if u == v:
                        break
                group_num += 1
            return now_ord, group_num

        for i in range(s._n):
            if ord[i] == -1:
                now_ord, group_num = dfs(dfs, i, now_ord, group_num)
        for i in range(s._n):
            ids[i] = group_num - 1 - ids[i]
        return [group_num, ids]

    # 強連結成分となっている頂点のリストのリスト トポロジカルソート済み
    # O(n + m)
    def scc(s):
        ids = s.scc_ids()
        group_num = ids[0]
        counts = [0] * group_num
        for x in ids[1]:
            counts[x] += 1
        groups = [[] for _ in range(group_num)]
        for i in range(s._n):
            groups[ids[1][i]].append(i)
        return groups

    class edge:
        def __init__(s, frm, to):
            s.frm = frm
            s.to = to


# -------最強ライブラリここまで------
def main():
    input = sys.stdin.readline
    n, m = list(map(int, input().split()))
    ab = [list(map(int, input().split())) for _ in range(m)]
    g = scc_graph(n)
    for i in range(m):
        u, v = ab[i]
        g.add_edge(u, v)
    scc = g.scc()
    print(len(scc))
    for v in scc:
        print(len(v), end=" ")
        for x in v:
            print(x, end=" ")
        print("")


main()

+import sys + +sys.setrecursionlimit(1000000) + + -        s.rg = {} -        if to in s.rg: -            s.rg[to].append(frm) -        else: -            s.rg[to] = [frm] -        def dfs(v): -            stack = [v] -            while stack: -                t = stack[-1] -                vis[t] = True -                if t not in s.g: -                    vs.append(stack.pop()) -                    continue -                for i in s.g[t]: -                    if not vis[i]: -                        stack.append(i) +        now_ord = group_num = 0 +        visited = [] +        low = [0] * s._n +        ord = [-1] * s._n +        ids = [0] * s._n +        # 再帰関数 +        def dfs(self, v, now_ord, group_num): +            low[v] = ord[v] = now_ord +            now_ord += 1 +            visited.append(v) +            if v in s.g: +                for to in s.g[v]: +                    if ord[to] == -1: +                        now_ord, group_num = self(self, to, now_ord, group_num) +                        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] = s._n +                    ids[u] = group_num +                    if u == v: -                else: -                    vs.append(stack.pop()) +                group_num += 1 +            return now_ord, group_num -        def rdfs(v, n): -            stack = [v] -            vis[v] = True -            ids[v] = n -            while stack: -                t = stack.pop() -                vis[t] = True -                if t not in s.rg: -                    continue -                for i in s.rg[t]: -                    if not vis[i]: -                        ids[i] = n -                        stack.append(i) - -        vis = [False] * s._n -        vs = [] -        ids = [-1] * s._n -            if not vis[i]: -                dfs(i) -        group_num = 0 -        vis = [False] * s._n -        for i in vs[::-1]: -            if not vis[i]: -                rdfs(i, group_num) -                group_num += 1 -        return group_num, ids +            if ord[i] == -1: +                now_ord, group_num = dfs(dfs, i, now_ord, group_num) +        for i in range(s._n): +            ids[i] = group_num - 1 - ids[i] +        return [group_num, ids] +    class edge: +        def __init__(s, frm, to): +            s.frm = frm +            s.to = to + -import sys - -