import sys
# Mărim limita de recursivitate pentru a susține grafuri mari (N <= 100.000)
sys.setrecursionlimit(200_000)
infile = open("ctc.in", "r")
outfile = open("ctc.out", "w")
# Citim prima linie: numărul de noduri (N) și numărul de muchii (M)
line = infile.readline()
if line:
nr_noduri, nr_muchii = map(int, line.strip().split())
# Inițializăm listele de adiacență pentru graf și graful transpus
adj = {i: [] for i in range(1, nr_noduri + 1)}
adj_t = {i: [] for i in range(1, nr_noduri + 1)}
# Citirea muchiilor
for _ in range(nr_muchii):
line = infile.readline()
if not line:
break
u, v = map(int, line.strip().split())
adj[u].append(v)
adj_t[v].append(u) # Construim graful transpus G^T
# Pasul 1: Căutare în adâncime (CA) pe G pentru a calcula timpii de terminare
visited = [False] * (nr_noduri + 1)
finish_order = []
def dfs1(node):
visited[node] = True
for neighbour in adj[node]:
if not visited[neighbour]:
dfs1(neighbour)
finish_order.append(node)
for i in range(1, nr_noduri + 1):
if not visited[i]:
dfs1(i)
# Pasul 2 și 3: Căutare în adâncime (CA) pe graful transpus G^T,
# considerând vârfurile în ordinea descrescătoare a timpilor de terminare
visited = [False] * (nr_noduri + 1)
scc_list = []
def dfs2(node, current_scc):
visited[node] = True
current_scc.append(node)
for neighbour in adj_t[node]:
if not visited[neighbour]:
dfs2(neighbour, current_scc)
# Parcurgem în ordine inversă (descrescătoare) a timpilor de terminare
for node in reversed(finish_order):
if not visited[node]:
current_scc = []
dfs2(node, current_scc)
scc_list.append(current_scc)
# Pasul 4: Scrierea rezultatelor în fișierul de ieșire ctc.out
outfile.write(str(len(scc_list)) + "\n")
for scc in scc_list:
outfile.write(" ".join(map(str, scc)) + "\n")
infile.close()
outfile.close()