#include <cassert>
#include <utility>
#include <vector>

class union_find {
private:
  using size_t = std::size_t;

  class node_type {
    friend union_find;

    size_t parent;
    size_t size;

    node_type(const size_t parent, const size_t size)
      : parent(parent), size(size) {}
  };

  std::vector<node_type> tree;

  size_t size() const { return tree.size(); }

public:
  union_find() = default;
  explicit union_find(const size_t n) : tree(n, node_type(n, 1)) {}

  size_t find(const size_t x) {
    assert(x < size());
    if (tree[x].parent == size())
      return x;
    else
      return tree[x].parent = find(tree[x].parent);
  }
  bool same(const size_t x, const size_t y) {
    assert(x < size());
    assert(y < size());
    return find(x) == find(y);
  }
  size_t size(const size_t x) {
    assert(x < size());
    return tree[find(x)].size;
  }

  void unite(size_t x, size_t y) {
    assert(x < size());
    assert(y < size());
    x = find(x);
    y = find(y);
    if (x != y) {
      if (tree[x].size < tree[y].size)
        std::swap(x, y);
      tree[x].size += tree[y].size;
      tree[y].parent = x;
    }
  }
};

#include <unordered_set>

class incremental_bridge_connected_components {
private:
  using size_t = std::size_t;

  union_find cc;
  union_find bcc;
  std::vector<size_t> bbf;

  size_t size() const { return bbf.size(); }
  size_t nil() const { return size(); }

  size_t parent(const size_t v) {
    if (bbf[v] == nil())
      return nil();
    else
      return bcc.find(bbf[v]);
  }
  size_t lca(size_t u, size_t v) {
    std::unordered_set<size_t> reached;
    while (true) {
      if (u != nil()) {
        if (!reached.insert(u).second)
          return u;
        u = parent(u);
      }
      std::swap(u, v);
    }
  }
  void condense_path(size_t u, const size_t v) {
    while (!bcc.same(u, v)) {
      const size_t next = parent(u);
      bbf[u] = bbf[v];
      bcc.unite(u, v);
      u = next;
    }
  }
  void link(const size_t x, const size_t y) {
    size_t v = x, prev = y;
    while (v != nil()) {
      const size_t next = bbf[v];
      bbf[v] = prev;
      prev = v;
      v = next;
    }
  }

public:
  incremental_bridge_connected_components() = default;
  explicit incremental_bridge_connected_components(const size_t n)
    : cc(n), bcc(n), bbf(n, n) {}

  void insert_edge(size_t u, size_t v) {
    assert(u < size());
    assert(v < size());
    u = bcc.find(u);
    v = bcc.find(v);
    if (cc.same(u, v)) {
      const size_t w = lca(u, v);
      condense_path(u, w);
      condense_path(v, w);
    }
    else {
      if (cc.size(u) > cc.size(v))
        std::swap(u, v);
      link(u, v);
      cc.unite(u, v);
    }
  }
  size_t find_block(const size_t u) {
    assert(u < size());
    return bcc.find(u);
  }
};

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

int main() {
  int n, m;
  std::cin >> n >> m;
  std::vector<std::pair<int, int>> v(m);
  for (auto& e : v) {
    std::cin >> e.first >> e.second;
    e = std::minmax({ e.first, e.second });
  }
  std::sort(v.begin(), v.end());
  incremental_bridge_connected_components ibcc(n);
  for (const auto& e : v) {
    ibcc.insert_edge(e.first, e.second);
  }
  //std::cout << std::endl;
  for (const auto& e : v) {
    if (ibcc.find_block(e.first) != ibcc.find_block(e.second)) {
      std::cout << e.first << " " << e.second << std::endl;
    }
  }
  return 0;
}


Measured memory_bytes: 3648