import sys
from collections import defaultdict
# First DFS to compute the finish time order
def dfs_first(graph, node, visited, stack):
visited.add(node)
for neighbor in graph[node]:
if neighbor not in visited:
dfs_first(graph, neighbor, visited, stack)
stack.append(node)
# Second DFS on the transposed graph to find SCCs
def dfs_second(transposed_graph, node, visited):
visited.add(node)
for neighbor in transposed_graph[node]:
if neighbor not in visited:
dfs_second(transposed_graph, neighbor, visited)
# Kosaraju's Algorithm to find SCCs
def kosaraju_scc(graph, n):
# Step 1: Perform first DFS to get the finishing times
visited = set()
stack = []
for node in range(n):
if node not in visited:
dfs_first(graph, node, visited, stack)
# Step 2: Transpose the graph (reverse all edges)
transposed_graph = defaultdict(list)
for node in graph:
for neighbor in graph[node]:
transposed_graph[neighbor].append(node)
# Step 3: Perform DFS on the transposed graph in order of decreasing finish times
visited.clear() # Reset visited for the second DFS
scc_count = 0
while stack:
node = stack.pop()
if node not in visited:
dfs_second(transposed_graph, node, visited)
scc_count += 1 # Each DFS from an unvisited node is a new SCC
return scc_count
# Read input
input_lines = sys.stdin.read().splitlines()
index = 0
graphs = []
# Parse input to create graphs
while index < len(input_lines):
n = int(input_lines[index]) # Number of nodes
index += 1
graph = defaultdict(list)
for i in range(n):
neighbors = list(map(int, input_lines[index].split()))
graph[i] = neighbors
index += 1
graphs.append((graph, n))
# Process each graph to compute the number of SCCs
results = []
for graph, n in graphs:
scc_count = kosaraju_scc(graph, n)
results.append(scc_count)
# Output the results
for result in results:
print(result)
aW1wb3J0IHN5cwpmcm9tIGNvbGxlY3Rpb25zIGltcG9ydCBkZWZhdWx0ZGljdAoKIyBGaXJzdCBERlMgdG8gY29tcHV0ZSB0aGUgZmluaXNoIHRpbWUgb3JkZXIKZGVmIGRmc19maXJzdChncmFwaCwgbm9kZSwgdmlzaXRlZCwgc3RhY2spOgogICAgdmlzaXRlZC5hZGQobm9kZSkKICAgIGZvciBuZWlnaGJvciBpbiBncmFwaFtub2RlXToKICAgICAgICBpZiBuZWlnaGJvciBub3QgaW4gdmlzaXRlZDoKICAgICAgICAgICAgZGZzX2ZpcnN0KGdyYXBoLCBuZWlnaGJvciwgdmlzaXRlZCwgc3RhY2spCiAgICBzdGFjay5hcHBlbmQobm9kZSkKCiMgU2Vjb25kIERGUyBvbiB0aGUgdHJhbnNwb3NlZCBncmFwaCB0byBmaW5kIFNDQ3MKZGVmIGRmc19zZWNvbmQodHJhbnNwb3NlZF9ncmFwaCwgbm9kZSwgdmlzaXRlZCk6CiAgICB2aXNpdGVkLmFkZChub2RlKQogICAgZm9yIG5laWdoYm9yIGluIHRyYW5zcG9zZWRfZ3JhcGhbbm9kZV06CiAgICAgICAgaWYgbmVpZ2hib3Igbm90IGluIHZpc2l0ZWQ6CiAgICAgICAgICAgIGRmc19zZWNvbmQodHJhbnNwb3NlZF9ncmFwaCwgbmVpZ2hib3IsIHZpc2l0ZWQpCgojIEtvc2FyYWp1J3MgQWxnb3JpdGhtIHRvIGZpbmQgU0NDcwpkZWYga29zYXJhanVfc2NjKGdyYXBoLCBuKToKICAgICMgU3RlcCAxOiBQZXJmb3JtIGZpcnN0IERGUyB0byBnZXQgdGhlIGZpbmlzaGluZyB0aW1lcwogICAgdmlzaXRlZCA9IHNldCgpCiAgICBzdGFjayA9IFtdCgogICAgZm9yIG5vZGUgaW4gcmFuZ2Uobik6CiAgICAgICAgaWYgbm9kZSBub3QgaW4gdmlzaXRlZDoKICAgICAgICAgICAgZGZzX2ZpcnN0KGdyYXBoLCBub2RlLCB2aXNpdGVkLCBzdGFjaykKCiAgICAjIFN0ZXAgMjogVHJhbnNwb3NlIHRoZSBncmFwaCAocmV2ZXJzZSBhbGwgZWRnZXMpCiAgICB0cmFuc3Bvc2VkX2dyYXBoID0gZGVmYXVsdGRpY3QobGlzdCkKICAgIGZvciBub2RlIGluIGdyYXBoOgogICAgICAgIGZvciBuZWlnaGJvciBpbiBncmFwaFtub2RlXToKICAgICAgICAgICAgdHJhbnNwb3NlZF9ncmFwaFtuZWlnaGJvcl0uYXBwZW5kKG5vZGUpCgogICAgIyBTdGVwIDM6IFBlcmZvcm0gREZTIG9uIHRoZSB0cmFuc3Bvc2VkIGdyYXBoIGluIG9yZGVyIG9mIGRlY3JlYXNpbmcgZmluaXNoIHRpbWVzCiAgICB2aXNpdGVkLmNsZWFyKCkgICMgUmVzZXQgdmlzaXRlZCBmb3IgdGhlIHNlY29uZCBERlMKICAgIHNjY19jb3VudCA9IDAKCiAgICB3aGlsZSBzdGFjazoKICAgICAgICBub2RlID0gc3RhY2sucG9wKCkKICAgICAgICBpZiBub2RlIG5vdCBpbiB2aXNpdGVkOgogICAgICAgICAgICBkZnNfc2Vjb25kKHRyYW5zcG9zZWRfZ3JhcGgsIG5vZGUsIHZpc2l0ZWQpCiAgICAgICAgICAgIHNjY19jb3VudCArPSAxICAjIEVhY2ggREZTIGZyb20gYW4gdW52aXNpdGVkIG5vZGUgaXMgYSBuZXcgU0NDCgogICAgcmV0dXJuIHNjY19jb3VudAoKIyBSZWFkIGlucHV0CmlucHV0X2xpbmVzID0gc3lzLnN0ZGluLnJlYWQoKS5zcGxpdGxpbmVzKCkKaW5kZXggPSAwCmdyYXBocyA9IFtdCgojIFBhcnNlIGlucHV0IHRvIGNyZWF0ZSBncmFwaHMKd2hpbGUgaW5kZXggPCBsZW4oaW5wdXRfbGluZXMpOgogICAgbiA9IGludChpbnB1dF9saW5lc1tpbmRleF0pICAjIE51bWJlciBvZiBub2RlcwogICAgaW5kZXggKz0gMQogICAgZ3JhcGggPSBkZWZhdWx0ZGljdChsaXN0KQoKICAgIGZvciBpIGluIHJhbmdlKG4pOgogICAgICAgIG5laWdoYm9ycyA9IGxpc3QobWFwKGludCwgaW5wdXRfbGluZXNbaW5kZXhdLnNwbGl0KCkpKQogICAgICAgIGdyYXBoW2ldID0gbmVpZ2hib3JzCiAgICAgICAgaW5kZXggKz0gMQoKICAgIGdyYXBocy5hcHBlbmQoKGdyYXBoLCBuKSkKCiMgUHJvY2VzcyBlYWNoIGdyYXBoIHRvIGNvbXB1dGUgdGhlIG51bWJlciBvZiBTQ0NzCnJlc3VsdHMgPSBbXQpmb3IgZ3JhcGgsIG4gaW4gZ3JhcGhzOgogICAgc2NjX2NvdW50ID0ga29zYXJhanVfc2NjKGdyYXBoLCBuKQogICAgcmVzdWx0cy5hcHBlbmQoc2NjX2NvdW50KQoKIyBPdXRwdXQgdGhlIHJlc3VsdHMKZm9yIHJlc3VsdCBpbiByZXN1bHRzOgogICAgcHJpbnQocmVzdWx0KQo=