#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;
using ll = long long;

struct Graph {
    Graph(const int v) : V{v}
    {
        edge.resize(v);
        rev_edge.resize(v);
    }
    void addEdge(const int from, const int to)
    {
        edge[from].push_back(to);
        rev_edge[to].push_back(from);
    }
    vector<vector<int>> edge;
    vector<vector<int>> rev_edge;
    const int V;
};

class BiconnectedComponent
{
public:
    BiconnectedComponent(const Graph& g_) : num{0}, comp_num{0}, size{g_.V}, bridge(0), ord(size, -1), low(size, 0), comp(size, -1)
    {
        for (int i = 0; i < size; i++) {
            if (ord[i] == -1) {
                bridge_dfs(g_, i);
            }
        }
        for (int i = 0; i < size; i++) {
            if (comp[i] >= 0) {
                continue;
            }
            comp_dfs(g_, i, comp_num);
            comp_num++;
        }
    }

    Graph toTree() const
    {
        Graph tree(comp_num);
        for (const auto& p : bridge) {
            tree.addEdge(comp[p.first], comp[p.second]);
            tree.addEdge(comp[p.second], comp[p.first]);
        }
        return tree;
    }
    const vector<pair<int, int>>& getEdge() const
    {
        return bridge;
    }
    const vector<int>& getComp() const
    {
        return comp;
    }

    const vector<pair<int, int>> getBridge() const
    {
        return bridge;
    }
    bool isBridge(const int i, const int j) const
    {
        return (ord[i] < ord[j]) ? (ord[i] < low[j]) : (ord[j] < low[i]);
    }

private:
    void bridge_dfs(const Graph& g_, const int s, const int par = -1)
    {
        ord[s] = num;
        low[s] = num;
        num++;
        for (const int to : g_.edge[s]) {
            if (to == par) {
                continue;
            }
            if (ord[to] >= 0) {
                low[s] = min(low[s], ord[to]);
            } else {
                bridge_dfs(g_, to, s);
                low[s] = min(low[s], low[to]);
                if (isBridge(s, to)) {
                    bridge.push_back(make_pair(s, to));
                }
            }
        }
    }

    void comp_dfs(const Graph& g_, const int s, const int c)
    {
        comp[s] = c;
        for (const int to : g_.edge[s]) {
            if ((comp[to] == -1) and (not isBridge(s, to))) {
                comp_dfs(g_, to, c);
            }
        }
    }

    int num;
    int comp_num;
    const int size;
    vector<pair<int, int>> bridge;
    vector<int> ord;
    vector<int> low;
    vector<int> comp;
};

int main()
{
    int V, E;
    cin >> V >> E;
    Graph g(V);
    using P = pair<int, int>;
    vector<P> edge;
    for (int i = 0; i < E; i++) {
        int s, t;
        cin >> s >> t;
        if (s > t) {
            swap(s, t);
        }
        g.addEdge(s, t);
        g.addEdge(t, s);
        edge.push_back(make_pair(s, t));
    }

    BiconnectedComponent bic(g);
    vector<P> b = bic.getBridge();
    for (auto& p : b) {
        if (p.first > p.second) {
            swap(p.first, p.second);
        }
    }
    sort(b.begin(), b.end());
    for (const auto& p : b) {
        cout << p.first << " " << p.second << endl;
    }

    return 0;
}

Measured memory_bytes: 5488