





import csv
import os

import pytest

from datasets import Dataset, DatasetDict, Features, NamedSplit, Value
from datasets.io.csv import CsvDatasetReader, CsvDatasetWriter

from ..utils import assert_arrow_memory_doesnt_increase, assert_arrow_memory_increases







def 			_SCREAMING_SNAKE_CASE    (       a ,						a  )				->				List[Any]:
					assert isinstance(a ,						a  )
					assert dataset.num_rows == 4
					assert dataset.num_columns == 3
					assert dataset.column_names == ["col_1", "col_2", "col_3"]
					for feature, expected_dtype in expected_features.items():
										assert dataset.features[feature].dtype == expected_dtype







@pytest.mark.parametrize('keep_in_memory' ,						[False, True]  )
def 			_SCREAMING_SNAKE_CASE    (       a ,						a ,						a  )				->				str:
					__A     :						Optional[Any]          =    tmp_path / 'cache'
					__A     :						int          =    {'col_1': 'int64', 'col_2': 'int64', 'col_3': 'float64'}
					with assert_arrow_memory_increases() if keep_in_memory else assert_arrow_memory_doesnt_increase():
										__A     :						Optional[int]          =    CsvDatasetReader(a ,						cache_dir=a ,						keep_in_memory=a  ).read()
					_check_csv_dataset(a ,						a  )







@pytest.mark.parametrize(
    'features' ,						[
        None,
        {'col_1': 'string', 'col_2': 'int64', 'col_3': 'float64'},
        {'col_1': 'string', 'col_2': 'string', 'col_3': 'string'},
        {'col_1': 'int32', 'col_2': 'int32', 'col_3': 'int32'},
        {'col_1': 'float32', 'col_2': 'float32', 'col_3': 'float32'},
    ] ,						)
def 			_SCREAMING_SNAKE_CASE    (       a ,						a ,						a  )				->				Dict:
					__A     :						Tuple          =    tmp_path / 'cache'
					# CSV file loses col_1 string dtype information: default now is "int64" instead of "string"
					__A     :						Optional[Any]          =    {'col_1': 'int64', 'col_2': 'int64', 'col_3': 'float64'}
					__A     :						List[str]          =    features.copy() if features else default_expected_features
					__A     :						Optional[Any]          =    (
					    Features({feature: Value(a  ) for feature, dtype in features.items()}  ) if features is not None else None
					)
					__A     :						List[Any]          =    CsvDatasetReader(a ,						features=a ,						cache_dir=a  ).read()
					_check_csv_dataset(a ,						a  )







@pytest.mark.parametrize('split' ,						[None, NamedSplit('train'  ), 'train', 'test']  )
def 			_SCREAMING_SNAKE_CASE    (       a ,						a ,						a  )				->				Dict:
					__A     :						Optional[int]          =    tmp_path / 'cache'
					__A     :						Dict          =    {'col_1': 'int64', 'col_2': 'int64', 'col_3': 'float64'}
					__A     :						str          =    CsvDatasetReader(a ,						cache_dir=a ,						split=a  ).read()
					_check_csv_dataset(a ,						a  )
					assert dataset.split == split if split else "train"







@pytest.mark.parametrize('path_type' ,						[str, list]  )
def 			_SCREAMING_SNAKE_CASE    (       a ,						a ,						a  )				->				Union[str, Any]:
					if issubclass(a ,						a  ):
										__A     :						Optional[Any]          =    csv_path
					elif issubclass(a ,						a  ):
										__A     :						Union[str, Any]          =    [csv_path]
					__A     :						Tuple          =    tmp_path / 'cache'
					__A     :						Dict          =    {'col_1': 'int64', 'col_2': 'int64', 'col_3': 'float64'}
					__A     :						Dict          =    CsvDatasetReader(a ,						cache_dir=a  ).read()
					_check_csv_dataset(a ,						a  )







def 			_SCREAMING_SNAKE_CASE    (       a ,						a ,						a=("train",)  )				->				Union[str, Any]:
					assert isinstance(a ,						a  )
					for split in splits:
										__A     :						Optional[int]          =    dataset_dict[split]
										assert dataset.num_rows == 4
										assert dataset.num_columns == 3
										assert dataset.column_names == ["col_1", "col_2", "col_3"]
										for feature, expected_dtype in expected_features.items():
															assert dataset.features[feature].dtype == expected_dtype







@pytest.mark.parametrize('keep_in_memory' ,						[False, True]  )
def 			_SCREAMING_SNAKE_CASE    (       a ,						a ,						a  )				->				Optional[int]:
					__A     :						List[str]          =    tmp_path / 'cache'
					__A     :						Union[str, Any]          =    {'col_1': 'int64', 'col_2': 'int64', 'col_3': 'float64'}
					with assert_arrow_memory_increases() if keep_in_memory else assert_arrow_memory_doesnt_increase():
										__A     :						int          =    CsvDatasetReader({'train': csv_path} ,						cache_dir=a ,						keep_in_memory=a  ).read()
					_check_csv_datasetdict(a ,						a  )







@pytest.mark.parametrize(
    'features' ,						[
        None,
        {'col_1': 'string', 'col_2': 'int64', 'col_3': 'float64'},
        {'col_1': 'string', 'col_2': 'string', 'col_3': 'string'},
        {'col_1': 'int32', 'col_2': 'int32', 'col_3': 'int32'},
        {'col_1': 'float32', 'col_2': 'float32', 'col_3': 'float32'},
    ] ,						)
def 			_SCREAMING_SNAKE_CASE    (       a ,						a ,						a  )				->				Optional[int]:
					__A     :						str          =    tmp_path / 'cache'
					# CSV file loses col_1 string dtype information: default now is "int64" instead of "string"
					__A     :						List[Any]          =    {'col_1': 'int64', 'col_2': 'int64', 'col_3': 'float64'}
					__A     :						Union[str, Any]          =    features.copy() if features else default_expected_features
					__A     :						Dict          =    (
					    Features({feature: Value(a  ) for feature, dtype in features.items()}  ) if features is not None else None
					)
					__A     :						str          =    CsvDatasetReader({'train': csv_path} ,						features=a ,						cache_dir=a  ).read()
					_check_csv_datasetdict(a ,						a  )







@pytest.mark.parametrize('split' ,						[None, NamedSplit('train'  ), 'train', 'test']  )
def 			_SCREAMING_SNAKE_CASE    (       a ,						a ,						a  )				->				Optional[Any]:
					if split:
										__A     :						Tuple          =    {split: csv_path}
					else:
										__A     :						List[str]          =    {'train': csv_path, 'test': csv_path}
					__A     :						List[Any]          =    tmp_path / 'cache'
					__A     :						List[Any]          =    {'col_1': 'int64', 'col_2': 'int64', 'col_3': 'float64'}
					__A     :						Union[str, Any]          =    CsvDatasetReader(a ,						cache_dir=a  ).read()
					_check_csv_datasetdict(a ,						a ,						splits=list(path.keys()  )  )
					assert all(dataset[split].split == split for split in path.keys()  )







def 			_SCREAMING_SNAKE_CASE    (       a  )				->				Union[str, Any]:
					with open(a ,						encoding='utf-8'  ) as csvfile:
										yield from csv.reader(a  )







def 			_SCREAMING_SNAKE_CASE    (       a ,						a  )				->				Optional[Any]:
					__A     :						int          =    tmp_path / 'cache'
					__A     :						List[str]          =    os.path.join(a ,						'tmp.csv'  )
					__A     :						List[str]          =    CsvDatasetReader({'train': csv_path} ,						cache_dir=a  ).read()
					CsvDatasetWriter(dataset['train'] ,						a ,						num_proc=1  ).write()

					__A     :						Dict          =    iter_csv_file(a  )
					__A     :						List[Any]          =    iter_csv_file(a  )

					for rowa, rowa in zip(a ,						a  ):
										assert rowa == rowa







def 			_SCREAMING_SNAKE_CASE    (       a ,						a  )				->				Dict:
					__A     :						Union[str, Any]          =    tmp_path / 'cache'
					__A     :						Any          =    os.path.join(a ,						'tmp.csv'  )
					__A     :						Tuple          =    CsvDatasetReader({'train': csv_path} ,						cache_dir=a  ).read()
					CsvDatasetWriter(dataset['train'] ,						a ,						num_proc=2  ).write()

					__A     :						Tuple          =    iter_csv_file(a  )
					__A     :						Optional[int]          =    iter_csv_file(a  )

					for rowa, rowa in zip(a ,						a  ):
										assert rowa == rowa







def 			_SCREAMING_SNAKE_CASE    (       a ,						a  )				->				int:
					__A     :						Dict          =    tmp_path / 'cache'
					__A     :						Dict          =    os.path.join(a ,						'tmp.csv'  )
					__A     :						int          =    CsvDatasetReader({'train': csv_path} ,						cache_dir=a  ).read()
					with pytest.raises(a  ):
										CsvDatasetWriter(dataset['train'] ,						a ,						num_proc=0  )











from __future__ import annotations







def 			_SCREAMING_SNAKE_CASE    (       a  )				->				List[str]:
					global graph, reversed_graph, scc, component, visit, stack
					if visit[u]:
										return
					__A     :						List[Any]          =    True
					for v in graph[u]:
										dfs(a  )
					stack.append(a  )







def 			_SCREAMING_SNAKE_CASE    (       a  )				->				Optional[Any]:
					global graph, reversed_graph, scc, component, visit, stack
					if visit[u]:
										return
					__A     :						str          =    True
					component.append(a  )
					for v in reversed_graph[u]:
										dfsa(a  )







def 			_SCREAMING_SNAKE_CASE    (       )				->				Optional[int]:
					global graph, reversed_graph, scc, component, visit, stack
					for i in range(a  ):
										dfs(a  )
					__A     :						str          =    [False] * n
					for i in stack[::-1]:
										if visit[i]:
															continue
										__A     :						Optional[Any]          =    []
										dfsa(a  )
										scc.append(a  )
					return scc


if __name__ == "__main__":
				# n - no of nodes, m - no of edges
				UpperCAmelCase  ,			UpperCAmelCase						:       List[str]        =					list(map(int, input().strip().split()))

				UpperCAmelCase						:       list[list[int]]        =					[[] for _ in range(n)]  # graph
				UpperCAmelCase						:       list[list[int]]        =					[[] for i in range(n)]  # reversed graph
				# input graph data (edges)
				for _ in range(m):
								UpperCAmelCase  ,			UpperCAmelCase						:       int        =					list(map(int, input().strip().split()))
								graph[u].append(v)
								reversed_graph[v].append(u)

				UpperCAmelCase						:       list[int]        =					[]
				UpperCAmelCase						:       list[bool]        =					[False] * n
				UpperCAmelCase						:       list[int]        =					[]
				UpperCAmelCase						:       list[int]        =					[]
				print(kosaraju())




