#include <vector>
#include <tuple>
#include <bitset>
#include <iostream>


struct union_find {
  std::vector<int> par;
  union_find(int N): par(N, -1) {}
  int root(int x) {
    return par[x] < 0 ? x : par[x] = root(par[x]);
  }
  std::tuple<int, int> unite(int x, int y) {
    x = root(x);
    y = root(y);
    if(x == y) return std::make_tuple(x, y);
    if(par[x] > par[y]) std::swap(x, y);
    par[x] += par[y];
    par[y] = x;
    return std::make_tuple(x, y);
  }
  int size(int x) {
    return -par[root(x)];
  }
};

#include <unistd.h>

namespace niu {

  struct fastin {
    static const int bufsize = 1 << 24;
    char buf[bufsize];
    char* iter;
    fastin() {
      iter = buf;
      for(int t = 0, k; (k = read(STDIN_FILENO, buf + t, sizeof(buf)) - t) > 0; t += k);
    }
    fastin& operator>>(int& num) {
      num = 0;
      bool neg = false;
      while(*iter < '+') iter++;
      if(*iter == '-') { neg = true; iter++; }
      else if(*iter == '+') iter++;
      while(*iter >= '0') num = 10 * num + *(iter++) - '0';
      if(neg) num = -num;
      return *this;
    } 
  } fin;
  struct fastout {
    static const int bufsize = 1 << 24;
    char buf[bufsize];
    char* iter;
    fastout() {
      iter = buf;
    }
    ~fastout() {
      for(int t = 0, k; (k = write(STDOUT_FILENO, buf + t, iter - buf - t)) > 0; t += k);
    }
    fastout& operator<<(int num) {
      static char tmp[20];
      if(num == 0) {
        *(iter++) = '0';
        return *this;
      }
      if(num < 0) {
        *(iter++) = '-';
        num = -num;
      }
      int i = 0;
      while(num) {
        tmp[i++] = num % 10;
        num /= 10;
      }
      while(i--) {
        *(iter++) = tmp[i] + '0';
      }
      return *this;
    }
    fastout& operator<<(char c) {
      *(iter++) = c;
      return *this;
    }
  } fout;
}

struct incremental_bridge_connectivity {
  static const int MAX_N = 202020;
  static const int MAX_E = 202020;
  std::vector<int> par;
  std::vector<std::pair<int, int>> edge;
  std::bitset<MAX_N> bit;
  std::bitset<MAX_E> bridge;
  union_find cg;
  union_find bcg;

  incremental_bridge_connectivity(int N)
    : par(N, -1), cg(N), bcg(N) {
    }

  int lca(int u, int v) {
    bit = 0;
    while(1) {
      if(u >= 0) {
        if(bit.test(u)) {
          return u;
        }
        bit.set(u);
        if(par[u] < 0) u = -1;
        else u = edge[par[u]].second;
      }
      std::swap(u, v);
    }
  }

  void compress_path(int v, int w) {
    while(v != w) {
      bcg.unite(v, w);
      bridge.reset(par[v]);
      v = edge[par[v]].second;
    }
  }

  void reverse_path(int v, int p) {
    while(true) {
      std::swap(edge[p].first, edge[p].second);
      std::swap(p, par[v]);
      if(p < 0) break;
      v = edge[p].second;
    }
  }

  int add_edge(int u, int v) {
    int ei = edge.size();
    edge.emplace_back(u, v);
    if(bcg.root(u) == bcg.root(v)) {
    }
    else if(cg.root(u) == cg.root(v)) {
      int w = lca(u, v);
      compress_path(u, w);
      compress_path(v, w);
    }
    else {
      bridge.set(ei);
      if(cg.size(u) < cg.size(v)) {
        std::swap(u, v);
        std::swap(edge.back().first, edge.back().second);
      }
      reverse_path(v, ei);
      cg.unite(u, v);
    }
    return ei;
  }

  int size(int v) {
    return bcg.size(v);
  }

  bool is_bridge(int ei) {
    return bridge.test(ei);
  }
};

#include <algorithm>

int main() {
  int N, M;
  niu::fin >> N >> M;
  incremental_bridge_connectivity ibc(N);
  for(int i =0;i < M;i++) {
    int a, b;
    niu::fin >> a >> b;
    ibc.add_edge(a, b);
  }
  std::vector<std::pair<int , int>> ans;
  for(int i = 0;i < M; i++) {
    if(ibc.is_bridge(i)) {
      ans.emplace_back(std::move(ibc.edge[i]));
      if(ans.back().first > ans.back().second) {
        std::swap(ans.back().first, ans.back().second);
      }
    }
  }
  std::sort(std::begin(ans), std::end(ans));
  for(auto&& e: ans) {
    niu::fout << e.first << ' ' << e.second << '\n';
  }
}



Measured memory_bytes: 4012