#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define rrep(i, n) for (int i = (int)(n - 1); i >= 0; i--)
#define all(x) (x).begin(), (x).end()
#define sz(x) int(x.size())
#define get_unique(x) x.erase(unique(all(x)), x.end());
typedef long long ll;
typedef complex<double> Complex;
const int INF = 1e9;
const ll MOD = 1e9 + 7;
const ll LINF = 1e18;
template <class T>
bool chmax(T& a, const T& b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <class T>
bool chmin(T& a, const T& b) {
    if (b < a) {
        a = b;
        return 1;
    }
    return 0;
}
template <class T>
vector<T> make_vec(size_t a) {
    return vector<T>(a);
}
template <class T, class... Ts>
auto make_vec(size_t a, Ts... ts) {
    return vector<decltype(make_vec<T>(ts...))>(a, make_vec<T>(ts...));
}
struct LowLink {
    int n;
    vector<int> ord, low, data, ArticulationPoints;
    vector<pair<int, int>> Bridge;
    LowLink(vector<vector<int>>& g, int s = 0)
        : n(sz(g)), ord(n, -1), low(n), data(n, -1) {
        int k = 0;
        dfs(s, -1, k, g);
        sort(all(ArticulationPoints));
        sort(all(Bridge));
    }
    int root(int x) {
        return (data[x] < 0) ? x : data[x] = root(data[x]);
    }
    bool unite(int x, int y) {
        x = root(x);
        y = root(y);
        if (x != y) {
            if (data[y] < data[x]) swap(x, y);
            data[x] += data[y];
            data[y] = x;
        }
        return x != y;
    }
    void dfs(int now, int pre, int& k, vector<vector<int>>& g) {
        ord[now] = k;
        k++;
        low[now] = ord[now];
        bool ok = 0;
        int cnt = 0;
        for (int nxt : g[now]) {
            if (nxt == pre) continue;
            if (ord[nxt] == -1) {
                dfs(nxt, now, k, g);
                chmin(low[now], low[nxt]);
                cnt++;
                if (low[nxt] >= ord[now]) {
                    ok = 1;
                }
                if (ord[now] < low[nxt]) {
                    Bridge.emplace_back(min(now, nxt), max(now, nxt));
                } else {
                    unite(now, nxt);
                }
            } else {
                chmin(low[now], ord[nxt]);
            }
        }
        if (pre == -1) {
            if (cnt > 1) ArticulationPoints.push_back(now);
        } else {
            if (ok) ArticulationPoints.push_back(now);
        }
    }
};
struct TwoEdgeConnectedComponents : LowLink {
    int n;
    vector<int> comp;
    TwoEdgeConnectedComponents(vector<vector<int>>& g, vector<vector<int>>& t,
                               int s = 0)
        : n(sz(g)), comp(n, -1), LowLink(g, s) {
        int k = 0;
        rep(i, n) {
            if (comp[root(i)] == -1) {
                comp[root(i)] = k;
                k++;
            }
        }
        t.resize(k);
        for (auto p : Bridge) {
            int u, v;
            tie(u, v) = p;
            t[comp[root(u)]].push_back(comp[root(v)]);
            t[comp[root(v)]].push_back(comp[root(u)]);
        }
    }
    int operator[](int& x) {
        return comp[root(x)];
    }
};
struct LowestCommonAncestor {
    int n, sn;
    vector<int> id, vs, dep;
    vector<pair<int, int>> node;
    LowestCommonAncestor(vector<vector<int>> g, int root = 0)
        : n(sz(g)), id(n), vs(n * 2 - 1), dep(n * 2 - 1) {
        int k = 0;
        dfs(root, -1, 0, k, g);
        sn = 1;
        while (sn < sz(dep)) {
            sn *= 2;
        }
        node.assign(2 * sn - 1, make_pair(INF, INF));
        for (int i = 0; i < sz(dep); i++) {
            node[sn + i - 1] = make_pair(dep[i], i);
        }
        for (int i = sn - 1; i >= 1; i--) {
            node[i] = min(node[i * 2 + 1], node[i * 2 + 2]);
        }
    }
    void dfs(int now, int pre, int d, int& k, const vector<vector<int>>& g) {
        id[now] = k;
        vs[k] = now;
        dep[k++] = d;
        for (int nxt : g[now]) {
            if (nxt == pre) continue;
            dfs(nxt, now, d + 1, k, g);
            vs[k] = now;
            dep[k++] = d;
        }
    }
    pair<int, int> query(int a, int b, int k = 0, int l = 0, int r = -1) {
        if (r < 0) r = sn;
        if (r <= a || b <= l) return make_pair(INF, INF);
        if (a <= l && r <= b) return node[k];
        auto vl = query(a, b, 2 * k + 1, l, (l + r) / 2);
        auto vr = query(a, b, 2 * k + 2, (l + r) / 2, r);
        return min(vl, vr);
    }
    int get(int u, int v) {
        int l = min(id[u], id[v]);
        int r = max(id[u], id[v]) + 1;
        return vs[query(l, r).second];
    }
    int depth(int u) {
        return dep[id[u]];
    }
    int dist(int u, int v) {
        return depth(u) + depth(v) - 2 * depth(get(u, v));
    }
};
int main() {
    int n, m;
    cin >> n >> m;
    vector<vector<int>> g(n);
    while (m--) {
        int u, v;
        cin >> u >> v;
        // u--;
        // v--;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    LowLink lk(g);
    for (auto p : lk.Bridge) cout << p.first << " " << p.second << endl;
}



Measured memory_bytes: 5784