// Original C++ solution (slower):
#include <bits/stdc++.h>



using namespace std;

typedef long long ll;

#define int ll



#define REP(i,n) for(ll i=0;i<n;++i)

#define SORT(name) sort(name.begin(), name.end())

#define ZERO(p) memset(p, 0, sizeof(p))

#define MINUS(p) memset(p, -1, sizeof(p))

#if 0

#  define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)

#else

#  define DBG(fmt, ...)

#endif



const ll LLINF = (1LL<<60);

const int INF = (1LL<<30);

const double DINF = std::numeric_limits<double>::infinity();

const int MOD = 1000000007;

#define MAX_N 100010



// Kahn のアルゴリズム

// 頂点 id の基数は 0 とする

class Kahn {

public:

    // n : 頂点数

    Kahn(int n) : m_N(n) {}

    Kahn() {}

    void Init(int n) { m_N = n; }



    // 頂点 from から頂点 to へ行く辺を追加

    void AddEdge(int from, int to) { m_G[from].push_back(to); }



    // トポロジカルソートに成功したら true

    // グラフが DAG でない場合は false

    bool TopologicalSort() {

        // 各頂点の入次数を計算 O(E)

        for(int i = 0; i < m_N; ++i) {

            for(int j = 0; j < m_G[i].size(); ++j) {

                m_Indeg[m_G[i][j]]++;

            }

        }

        // 入次数 0 の頂点を stack に入れる O(V)

        for(int i = 0; i < m_N; ++i) {

            if(m_Indeg[i] == 0) { m_St.push(i); }

        }

        while(m_St.size() > 0) {

            int u = m_St.top(); m_St.pop();

            m_KahnAns.push_back(u);      // 入次数 0 の頂点を結果列に挿入

            for(auto& v : m_G[u]) {

                m_Indeg[v]--;

                if(m_Indeg[v] == 0) { m_St.push(v); }

            }

        }

        // m_KahnAns にトポロジカルソート結果が入る

        return (m_KahnAns.size() == m_N) ? true : false;

    }



    void MakePos(vector<ll>& v) {

        REP(i, m_N) {

            DBG("%lld ", m_KahnAns[i]);

            v[m_KahnAns[i]] = i;

        }

        DBG("\n");

    }



private:

    int         m_N;                // N: 頂点数

    vector<int> m_G[MAX_N];         // ind から val に向かって延びている辺の隣接リスト

    int         m_Indeg[MAX_N];     // 各頂点の入次数

    stack<int>  m_St;               // 入次数 0 の頂点の集合

    vector<int> m_KahnAns;

};



ll N, M;

Kahn* k1;



vector<ll> origin[MAX_N];   // ノード i に入ってくるエッジの指し元

vector<ll> indeg;           // にゅうじすう



vector<ll> pos;             // ソート後の位置



bool dfs(ll goal, ll cur) {

    if(cur == goal) { return true; }

    for(auto& nxt : origin[cur]) {

        if(dfs(goal, nxt)) { return true; }

    }

    return false;

}



// 辺 from, to を使わなくても cand が child の祖先なら true

bool isParent(ll child, ll cand) {

    for(auto& nxt : origin[child]) {

        if(nxt == cand) { continue; }

        if(dfs(cand, nxt)) { return true; }

    }

    return false;

}



signed main()

{

    cin >> N >> M;

    Kahn* k1 = new Kahn(N);

    REP(i, N + M - 1) {

        ll a, b;

        cin >> a >> b;

        a--; b--;

        k1->AddEdge(a, b);



        origin[b].push_back(a);

    }

    bool ret = k1->TopologicalSort();

    assert(ret);



    pos.assign(N, 0);

    k1->MakePos(pos);



    REP(i, N) {

        // 入じ数が 2 以上なら 1 まで減らす

        if(origin[i].size() >= 2) {

            ll val = -1;

            ll ind = -1;

            for(auto& cand : origin[i]) {

                // この辺を消すと親子関係じゃなくなるなら、残す

                //if(!isParent(i, cand)) {

                //    printf("%lld\n", cand + 1);

                //    break;

                //}



                // 一番近いやつを残す

                if(pos[cand] > val) {

                    ind = cand;

                    val = pos[cand];

                }

            }

            assert(ind >= 0);

            printf("%lld\n", ind + 1);

        }

        else if(origin[i].size() == 0) {

            printf("0\n");

        }

        else {

            printf("%lld\n", origin[i][0] + 1);

        }

    }







    return 0;

}


// Optimized solution to the same problem (faster):
#include <bits/stdc++.h>



using namespace std;

typedef long long ll;

#define int ll



#define REP(i,n) for(ll i=0;i<n;++i)

#define SORT(name) sort(name.begin(), name.end())

#define ZERO(p) memset(p, 0, sizeof(p))

#define MINUS(p) memset(p, -1, sizeof(p))

#if 1

#  define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)

#else

#  define DBG(fmt, ...)

#endif



const ll LLINF = (1LL<<60);

const int INF = (1LL<<30);

const double DINF = std::numeric_limits<double>::infinity();

const int MOD = 1000000007;

#define MAX_N 100010



// Kahn のアルゴリズム O(E + V)

// 頂点 id の基数は 0 とする

class Kahn {

public:

    // n : 頂点数

    Kahn(int n) { Init(n); }

    Kahn() {}

    void Init(int n) {

        m_N = n;

        m_G.assign(m_N, vector<int>());

        m_G2.assign(m_N, vector<int>());

        m_Indeg.assign(m_N, 0);

        m_Zeros = priority_queue< pair<int, int> >();

    }



    // 頂点 from から頂点 to へ行く辺を追加

    void AddEdge(int from, int to) {

        m_G[from].push_back(to);

        m_G2[to].push_back(from);

    }



    // O(E + V)

    // トポロジカルソートに成功したら true

    // グラフが DAG でない場合は false

    //

    // 頂点に優先度をつけたトポロジカルソートも可能。

    // m_Zeros の first に入れる優先度を設定すると良い

    bool TopSort() {

        // 各頂点の入次数を計算 O(E)

        for(int i = 0; i < m_N; ++i) {

            m_Indeg[i] = static_cast<int>(m_G2[i].size());

        }

        // 入次数 0 の頂点を stack に入れる O(V)

        for(int i = 0; i < m_N; ++i) {

            // !!! 入れ方に優先度を持たせたい場合はここを工夫する !!!

            if(m_Indeg[i] == 0) { m_Zeros.push(make_pair(777, i)); }

        }

        while(m_Zeros.size() > 0) {

            // 入次数が 0 の頂点をとってくる

            pair<int, int> u = m_Zeros.top(); m_Zeros.pop();

            m_KahnAns.push_back(u.second);      // 入次数 0 の頂点を結果列に挿入

            // この頂点から伸びている辺を削除。新たに入次数 0 になるものがあるなら追加

            for(auto& v : m_G[u.second]) {

                m_Indeg[v]--;

                // !!! 入れ方に優先度を持たせたい場合はここを工夫する !!!

                if(m_Indeg[v] == 0) { m_Zeros.push(make_pair(777, v)); }

            }

        }

        // m_KahnAns にトポロジカルソート結果が入る

        return (m_KahnAns.size() == m_N) ? true : false;

    }



    // 頂点 i の入次数を得る O(1)

    int GetIndeg(int i) { return static_cast<int>(m_G2[i].size()); }



    // 頂点 i の指し先 vector を取得 O(1)

    const vector<int>& GetForward(int i) { return m_G[i]; }

    // 頂点 i の指され元 vector を取得 O(1)

    const vector<int>& GetBackward(int i) { return m_G2[i]; }



    // トポロジカルソートの結果を得る O(V)

    // ret に結果が入る。TopSort 後でないと無効

    void GetResult(vector<int>& ret) {

        assert(m_KahnAns.size() == m_N);

        ret.clear();

        copy(m_KahnAns.begin(), m_KahnAns.end(), back_inserter(ret));

    }



    // O(V)

    // トポロジカルソート後、各頂点がどの位置になったかの逆引き vector を得る

    // ret[i] = val → 頂点 i はソート後位置 val になる

    // ret に結果が入る。TopSort 後でないと無効

    void GetPos(vector<int>& ret) {

        assert(m_KahnAns.size() == m_N);

        ret.resize(m_N);

        for(int i = 0; i < m_N; ++i) { ret[m_KahnAns[i]] = i; }

    }



private:

    // 入力必須

    int                                 m_N;        // 頂点数

    vector< vector<int> >               m_G;        // グラフの隣接リスト

    vector< vector<int> >               m_G2;       // m_G のエッジ向きが逆方向の隣接リスト

    // 一時利用

    vector<int>                         m_Indeg;    // 各頂点の入次数(TopSort後使い捨てられる)

    priority_queue< pair<int, int> >    m_Zeros;    // 入次数 0 の頂点の集合(TopSort後使い捨てられる)

    // 答え

    vector<int>                         m_KahnAns;  // ソート結果。ソート後のノード id が入る

};



int N, M;

Kahn kahn;



vector<int> pos;             // ソート後の位置



signed main()

{

    cin >> N >> M;

    kahn.Init(N);

    REP(i, N + M - 1) {

        int a, b;

        cin >> a >> b;

        a--; b--;

        kahn.AddEdge(a, b);

    }

    bool ret = kahn.TopSort();

    assert(ret);



    pos.assign(N, 0);

    kahn.GetPos(pos);



    REP(i, N) {

        // 入次数が 2 以上なら 1 まで減らす

        if(kahn.GetIndeg(i) >= 2) {

            int val = -1;

            int ind = -1;

            for(auto& cand : kahn.GetBackward(i)) {

                // 一番近いやつを残す

                if(pos[cand] > val) {

                    ind = cand;

                    val = pos[cand];

                }

            }

            assert(ind >= 0);

            printf("%lld\n", ind + 1);

        }

        else if(kahn.GetIndeg(i) == 0) {

            printf("0\n");

        }

        else {

            printf("%lld\n", kahn.GetBackward(i)[0] + 1);

        }

    }



    return 0;

}


// Fastest known solution for this problem: