import sys
import threading
# 1. Marim limita logica de recursivitate
sys.setrecursionlimit(200000)
def solve():
# 2. Citire Ultra-Rapida
try:
with open("ctc.in", "r") as f:
data = f.read().split()
except FileNotFoundError:
return
if not data:
return
iterator = iter(data)
try:
n = int(next(iterator))
m = int(next(iterator))
adj = [[] for _ in range(n + 1)]
adj_rev = [[] for _ in range(n + 1)]
for _ in range(m):
x = int(next(iterator))
y = int(next(iterator))
adj[x].append(y)
adj_rev[y].append(x)
except StopIteration:
return
# 3. OPTIMIZARE: Inlocuim set() cu liste de integeri (0/1)
# Este mult mai rapid si consuma mai putina memorie
visited1 = [0] * (n + 1)
visited2 = [0] * (n + 1)
stack = []
# --- DFS 1 (Pe graf normal) ---
def df1(nod):
visited1[nod] = 1
for vecin in adj[nod]:
if visited1[vecin] == 0:
df1(vecin)
stack.append(nod)
for i in range(1, n + 1):
if visited1[i] == 0:
df1(i)
# --- DFS 2 (Pe graf transpus) ---
def df2(nod, componenta):
visited2[nod] = 1
componenta.append(nod)
for vecin in adj_rev[nod]:
if visited2[vecin] == 0:
df2(vecin, componenta)
solutie = []
# Procesam stiva invers (LIFO)
while stack:
nod = stack.pop()
if visited2[nod] == 0:
comp_noua = []
df2(nod, comp_noua)
solutie.append(comp_noua)
# 4. Scriere Rapida
with open("ctc.out", "w") as f:
f.write(f"{len(solutie)}\n")
for comp in solutie:
# *comp afiseaza elementele separate prin spatiu fara bucle lente
print(*comp, file=f)
def main():
solve()
if __name__ == "__main__":
# 5. TRUCUL PENTRU STACK OVERFLOW
# Alocam un thread cu stack size de 64MB (suficient pentru 200.000 recursivitati)
# Fara asta, iei KILLED BY SIGNAL sau RUNTIME ERROR pe teste mari
threading.stack_size(67108864) # 64MB
thread = threading.Thread(target=main)
thread.start()
thread.join()