Problem:
Score : 500 points

Problem Statement

There is a rooted tree (see Notes) with N vertices numbered 1 to N.
Each of the vertices, except the root, has a directed edge coming from its parent.
Note that the root may not be Vertex 1.

Takahashi has added M new directed edges to this graph.
Each of these M edges, u \rightarrow v, extends from some vertex u to its descendant v.

You are given the directed graph with N vertices and N-1+M edges after Takahashi added edges.
More specifically, you are given N-1+M pairs of integers, (A_1, B_1), ..., (A_{N-1+M}, B_{N-1+M}), which represent that the i-th edge extends from Vertex A_i to Vertex B_i.

Restore the original rooted tree.

Notes

For "tree" and other related terms in graph theory, see the article in Wikipedia, for example.

Constraints

3 \leq N

1 \leq M

N + M \leq 10^5

1 \leq A_i, B_i \leq N

A_i \neq B_i

If i \neq j, (A_i, B_i) \neq (A_j, B_j).

The graph in input can be obtained by adding M edges satisfying the condition in the problem statement to a rooted tree with N vertices.

Input

Input is given from Standard Input in the following format:

N M
A_1 B_1
:
A_{N-1+M} B_{N-1+M}

Output

Print N lines.
In the i-th line, print 0 if Vertex i is the root of the original tree, and otherwise print the integer representing the parent of Vertex i in the original tree.

Note that it can be shown that the original tree is uniquely determined.

Sample Input 1

3 1
1 2
1 3
2 3

Sample Output 1

0
1
2

The graph in this input is shown below:

It can be seen that this graph is obtained by adding the edge 1 \rightarrow 3 to the rooted tree 1 \rightarrow 2 \rightarrow 3.

Sample Input 2

6 3
2 1
2 3
4 1
4 2
6 1
2 6
4 6
6 5

Sample Output 2

6
4
2
0
6
2

Solution in C++14 (GCC 5.4.1) (judge verdict: Time Limit Exceeded)

#include <algorithm>
#include <cassert>
#include <cstdint>
#include <iostream>
#include <iterator>
#include <map>
#include <queue>
#include <stack>
#include <unordered_set>
#include <vector>

using namespace std;

template <typename N = std::size_t, typename E = std::size_t>
class SparseGraph
{
public:
    using NodeType = N;
    using EdgeType = E;
    using NeighborListType = std::unordered_set<std::size_t>;

    SparseGraph(bool undirected = true) noexcept
        : undirected_(undirected)
    {
    }

    void push_node(NodeType n) noexcept
    {
        nodes_.push_back(n);
        neighbor_list_.emplace_back();
    }

    void connect(const std::size_t from, const std::size_t to, const EdgeType edge = EdgeType()) noexcept
    {
        if (undirected_)
        {
            neighbor_list_[from].insert(to);
            neighbor_list_[to].insert(from);
            edges_[std::make_pair(std::min(from, to), std::max(from, to))] = edge;
        }
        else
        {
            neighbor_list_[from].insert(to);
            edges_[std::make_pair(from, to)] = edge;
        }
    }

    void disconnect(const std::size_t from, const std::size_t to) noexcept
    {
        if (undirected_)
        {
            neighbor_list_[from].erase(to);
            neighbor_list_[to].erase(from);
            edges_.erase(std::make_pair(std::min(from, to), std::max(from, to)));
        }
        else
        {
            neighbor_list_[from].erase(to);
            edges_.erase(std::make_pair(from, to));
        }
    }

    const NodeType& node(const std::size_t index) const noexcept
    {
        return nodes_.at(index);
    }

    const EdgeType& edge(const std::size_t from, const std::size_t to) const noexcept
    {
        if (undirected_)
        {
            auto key = std::make_pair(std::min(from, to), std::max(from, to));
            return edges_.at(key);
        }
        else
        {
            auto key = std::make_pair(from, to);
            return edges_.at(key);
        }
    }

    NodeType& node(const std::size_t index) noexcept
    {
        return nodes_.at(index);
    }

    EdgeType& edge(const std::size_t from, const std::size_t to) noexcept
    {
        if (undirected_)
        {
            auto key = std::make_pair(std::min(from, to), std::max(from, to));
            return edges_.at(key);
        }
        else
        {
            auto key = std::make_pair(from, to);
            return edges_.at(key);
        }
    }

    const NeighborListType&
    neighbor(const std::size_t index) const noexcept
    {
        return neighbor_list_[index];
    }

    std::size_t size() const noexcept
    {
        return neighbor_list_.size();
    }

private:
    using EdgeMap = std::map<std::pair<std::size_t, std::size_t>, EdgeType>;

    std::vector<NeighborListType> neighbor_list_;

    EdgeMap edges_;

    std::vector<NodeType> nodes_;

    bool undirected_;
};

template <typename GraphType>
std::vector<std::size_t> topological_order(const GraphType& graph)
{
    std::vector<bool> decided(graph.size(), false);
    std::vector<std::size_t> order;

    for (int ns = 0; ns < graph.size(); ns++)
    {
        if (!decided[ns])
        {
            // (node, neihgbor index)
            stack<std::pair<int, int>> s;
            s.emplace(ns, 0);

            while (!s.empty())
            {
                int n, i;
                tie(n, i) = s.top();
                s.pop();

                if (!decided[n])
                {
                    // 帰りがけのタイミング
                    if (i == graph.neighbor(n).size())
                    {
                        decided[n] = true;
                        order.push_back(n);
                    }
                    else
                    {
                        s.emplace(n, i + 1);
                        for (auto next : graph.neighbor(n))
                        {
                            if (!decided[next])
                            {
                                s.emplace(next, 0);
                            }
                        }
                    }
                }
            }
        }
    }
    assert(order.size() == graph.size());
    reverse(order.begin(), order.end());
    return order;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;
    cin >> n >> m;

    SparseGraph<> graph(false);
    for (int i = 0; i < n; i++)
    {
        graph.push_node(0);
    }

    vector<int> ts(n, 0);
    for (int i = 0; i < m + n - 1; i++)
    {
        int f, t;
        cin >> f >> t;
        graph.connect(f - 1, t - 1);
        ts[t - 1]++;
    }

    const int root = distance(ts.begin(), find(ts.begin(), ts.end(), 0));
    graph.node(root) = 0;

    auto order = topological_order(graph);
    vector<int> rev(n, 0);
    for (int i = 0; i < n; i++)
    {
        rev[order[i]] = i;
    }

    vector<vector<int>> rev_neighbor(n);

    for (int v : order)
    {
        for (int nv : graph.neighbor(v))
        {
            rev_neighbor[nv].push_back(v);
        }
    }

    for (int i = 1; i < n; i++)
    {
        int v = order[i];
        int selected = 0;
        int max_i = -1;
        for (int rv : rev_neighbor[v])
        {
            if (max_i <= rev[rv])
            {
                max_i = rev[rv];
                selected = rv;
            }
        }
        graph.node(v) = graph.node(selected) + 1;
    }

    vector<int> result(n, -1);
    result[root] = 0;

    for (int v = 0; v < graph.size(); v++)
    {
        for (int nv : graph.neighbor(v))
        {
            if (graph.node(v) + 1 == graph.node(nv))
            {
                result[nv] = v + 1;
            }
        }
    }
    for (auto v : result)
    {
        cout << v << endl;
    }
}