mod utils {
    use std::error::Error;
    use std::io::stdin;
    use std::str::FromStr;

    #[allow(dead_code)]
    pub fn read_line<T>() -> Result<Vec<T>, Box<Error>>
    where
        T: FromStr,
        T::Err: 'static + Error,
    {
        let mut line = String::new();
        let _ = stdin().read_line(&mut line)?;
        let parsed_line = line.split_whitespace()
            .map(|x| x.parse::<T>())
            .collect::<Result<Vec<T>, T::Err>>()?;

        Ok(parsed_line)
    }

    #[allow(dead_code)]
    pub fn read_lines<T>(n: usize) -> Result<Vec<Vec<T>>, Box<Error>>
    where
        T: FromStr,
        T::Err: 'static + Error,
    {
        (0..n).map(|_| read_line()).collect()
    }
}

type NodeId = usize;
use std::collections::VecDeque;

struct TopologicalSort {
    n_nodes: usize,
    n_edges: usize,
    edges: Vec<Vec<usize>>,
    indegrees: Vec<usize>,
    outdegrees_list: Vec<Vec<usize>>,
    checked: Vec<usize>,
    result: Vec<NodeId>,
    queue: VecDeque<usize>,
}

impl TopologicalSort {
    fn sort(&mut self) {
        for i_node in 0..self.n_nodes {
            if self.indegrees[i_node] == 0 && self.checked[i_node] == 0 {
                self.search(i_node);
            }
        }
    }

    fn search(&mut self, i_node: usize) {
        self.queue.push_back(i_node);
        self.checked[i_node] = 1;

        while !self.queue.is_empty() {
            let front = self.queue.pop_front().unwrap();
            self.result.push(front);

            for &neighbor in &self.outdegrees_list[front] {
                self.indegrees[neighbor] -= 1;

                if self.indegrees[neighbor] == 0 && self.checked[neighbor] == 0 {
                    self.checked[neighbor] = 1;
                    self.queue.push_back(neighbor);
                }
            }
        }
    }
}

struct TopologicalSortBuilder {
    n_nodes: usize,
    edges: Vec<Vec<usize>>,
}

impl TopologicalSortBuilder {
    fn new(n_nodes: usize, edges: Vec<Vec<usize>>) -> TopologicalSortBuilder {
        TopologicalSortBuilder {
            n_nodes: n_nodes,
            edges: edges,
        }
    }

    fn finalize(self) -> TopologicalSort {
        let mut indegrees = vec![0 as usize; self.n_nodes];
        for edge in &self.edges {
            indegrees[edge[1]] += 1;
        }

        let mut outdegrees = vec![vec![]; self.n_nodes];
        for edge in &self.edges {
            outdegrees[edge[0]].push(edge[1]);
        }

        TopologicalSort {
            n_nodes: self.n_nodes,
            n_edges: self.edges.len(),
            edges: self.edges,
            indegrees: indegrees,
            outdegrees_list: outdegrees,
            result: Vec::new(),
            checked: vec![0; self.n_nodes],
            queue: VecDeque::new(),
        }
    }
}

fn solve() -> Result<(), Box<std::error::Error>> {
    let header = utils::read_line::<usize>()?;
    let n_nodes = header[0];
    let n_edges = header[1];
    let edges = utils::read_lines::<usize>(n_edges)?;

    let mut tp = TopologicalSortBuilder::new(n_nodes, edges).finalize();
    tp.sort();
    for x in tp.result {
        println!("{}", x);
    }
    Ok(())
}

fn main() {
    match solve() {
        Err(err) => panic!("{}", err),
        _ => (),
    };
}



Measured memory_bytes: 7056