Problem:
Bridges
Find bridges of an undirected graph
G(V, E)
.
A bridge (also known as a cut-edge) is an edge whose deletion increase the number of connected components.
Input
|V|
|E|
s
0
t
0
s
1
t
1
:
s
|E|-1
t
|E|-1
, where
|V|
is the number of nodes and
|E|
is the number of edges in the graph. The graph nodes are named with the numbers 0, 1,...,
|V|
-1 respectively.
s
i
and
t
i
represent source and target nodes of
i
-th edge (undirected).
Output
A list of
bridges
of the graph ordered by name. For each bridge, names of its end-ponints, source and target (source < target), should be printed separated by a space. The sources should be printed ascending order, then the target should also be printed ascending order for the same source.
Constraints
1 ≤
|V|
≤ 100,000
0 ≤
|E|
≤ 100,000
The graph is connected
There are no parallel edges
There are no self-loops
Sample Input 1
4 4
0 1
0 2
1 2
2 3
Sample Output 1
2 3
Sample Input 2
5 4
0 1
1 2
2 3
3 4
Sample Output 2
0 1
1 2
2 3
3 4

Submitted solutions:

code_snippet: #include<bits/stdc++.h>
using namespace std;

vector<pair<int, int>> br;
vector<vector<int>> adj;
int Time=0;
vector<int> low, disc;

void dfsBR(int u, int p) {
  low[u] = disc[u] = ++Time;
  for (int& v : adj[u]) {
    if (v == p) continue; // we don't want to go back through the same path.
                          // if we go back is because we found another way back
    if (!disc[v]) { // if V has not been discovered before
      dfsBR(v, u);  // recursive DFS call
      if (disc[u] < low[v]) // condition to find a bridge
        br.push_back({u, v});
      low[u] = min(low[u], low[v]); // low[v] might be an ancestor of u
    } else // if v was already discovered means that we found an ancestor
      low[u] = min(low[u], disc[v]); // finds the ancestor with the least discovery time
  }
}

void BR() {
  low = disc = vector<int>(adj.size());
  Time = 0;
  for (int u = 0; u < adj.size(); u++)
    if (!disc[u])
      dfsBR(u, u);
}

int main(){
    int n;
    cin >> n;
    int m;
    cin >> m;
    adj.assign(n+1,{});
    for(int i=0;i<m;i++){
      int x,y;
      cin >> x>> y;
      adj[x].push_back(y);
      adj[y].push_back(x);
    }
    low.assign(n+1,0);
    disc.assign(n+1,0);
    BR();
    for(int i=0;i<br.size();i++){
        if(br[i].first>br[i].second) swap(br[i].first, br[i].second);
    }
    sort(br.begin(),br.end());
    for(auto bd:br){
        cout << bd.first << ' ' << bd.second << '\n';
    }
}
accuracy: 1
time_ms: 10
memory_kb: 4868
final_rank: 4

code_snippet: #include <iostream>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
#include <iomanip>
#include <numeric>
#include <queue>
#include <stack>
using namespace std;
using ll = long long;
struct Edge {
	int to;
	int id;
};
vector<vector<Edge>> G;
vector<int> ord, low;
vector<bool> is_bridge;
int inf = (int)1e9;
void dfs(int v, int par, int k) {
	ord[v] = k;
	for (auto nv : G[v]) {
		if (ord[nv.to] == -1) {
			 dfs(nv.to, v, k+1);
			 low[v] = min(low[v], low[nv.to]);
			 if (ord[v] < low[nv.to]) {
			 	is_bridge[nv.id] = true;
			 } else {
			 	is_bridge[nv.id] = false;
			 }
		} else if (nv.to != par) {
			is_bridge[nv.id] = false;
			low[v] = min(low[v], ord[nv.to]);
		}
	}
}
int main() {
	int N, M;cin >> N >> M;	
	G.assign(N, {});
	ord.assign(N, -1);
	low.assign(N, inf);
	is_bridge.assign(M, false);
	vector<int> A(M), B(M);
	for (int i = 0;i < M;i++) {
		int u, v;cin >> u >> v;
		A[i] = u;B[i] = v;
		G[u].push_back({v, i});
		G[v].push_back({u, i});
	}
	dfs(0, 0, 0);
	vector<pair<int, int>> res;
	for (int i = 0;i < M;i++) if (is_bridge[i]) res.push_back({min(A[i],B[i]), max(A[i],B[i])});
	sort(res.begin(),res.end());
	for (auto v : res) cout << v.first << " " << v.second << endl;
}
accuracy: 1
time_ms: 10
memory_kb: 5716
final_rank: 11

code_snippet: #include <bits/stdc++.h>

//#pragma GCC optimize("Ofast")
//#pragma GCC target("avx,avx2,fma")
//#pragma GCC optimization("unroll-loops")

using namespace std;

#define int long long
#define double long double
#define uint unsigned int
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define is2pow(n) (n && (!(n & (n-1))))
#define OPTIMIZE ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);

const int MOD = 1e15 + 7;
const int MAX_N = 2e5;
const int MAX_K = 80;
const long long INF = 1e18;
const double EPS = 1e-6;

int binPow(int base, int pow, int mod) {
    if (pow == 0)
        return 1 % mod;
    int res = 1;
    while (pow != 0) {
        if (pow & 1)
            res = res * base % mod;
        base = base * base % mod;
        pow = pow >> 1;
    }
    return res;
}

struct Edge {
    int from, to, w;

    Edge(int u,int v,int w = 1) {
        from = u, to = v, this->w = w;
    }
};

struct BridgeFinder {
    // Time: O(n + m), Space: O(n + m)
    vector<vector<Edge>> graph;
    vector<int> visited, tup, tin;
    vector<Edge> bridges;
    int n;

    explicit BridgeFinder(const vector<vector<Edge>>& g) :
        n(g.size()), graph(g), visited(g.size()), tup(g.size()), tin(g.size()) {
    }

    void dfs(int current, int parent = -1, int height = 0) {
        visited[current] = 1, tin[current] = tup[current] = height;
        Edge parentEdge{0, 0};
        int cntSeenPar = 0;
        for (const Edge& edge: graph[current]) {
            if (edge.to == parent) {
                cntSeenPar++;
                parentEdge = edge;
                continue;
            }
            if (!visited[edge.to])
                dfs(edge.to, current, height + 1);
            tup[current] = min(tup[current], tup[edge.to]);
        }
        if (tup[current] == tin[current] && parent != -1 && cntSeenPar == 1) // found bridge, add new component
            bridges.emplace_back(parentEdge);
    }

    void findBridges() {
        for (int u = 0; u < n; u++)
            if (!visited[u])
                dfs(u);
    }
};

void solve() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    vector<vector<Edge>> g(n);
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        g[u].emplace_back(u, v);
        g[v].emplace_back(v, u);
    }
    BridgeFinder finder(g);
    finder.findBridges();
    vector<pair<int, int>> bridges;
    for (const auto& edge: finder.bridges) {
        int u = edge.from;
        int v = edge.to;
        if (u > v)
            swap(u, v);
        bridges.emplace_back(u, v);
    }
    sort(bridges.begin(), bridges.end());
    for (auto& [u,v]: bridges) {
        cout << u << " " << v << "\n";
    }
}

#define TES
#define LOCA
#define FIL

int32_t main() {
    OPTIMIZE
#ifdef FILE
    freopen("path_easy.in", "r", stdin); freopen("path_easy.out", "w", stdout);
#endif
#ifdef LOCAL
    freopen("/home/rekname/data/C++ Projects/codedforceProject/input.txt", "r", stdin);
#endif
    int t = 1;
#ifdef TEST
    cin >> t;
#endif
    while (t--) {
        solve();
    }
}
accuracy: 1
time_ms: 10
memory_kb: 10324
final_rank: 20

code_snippet: #include<bits/stdc++.h>
using namespace std;

#define int long long
#define rep(i,n) for(int i=0;i<(n);i++)
#define pii pair<int,int>
#define pipii pair<int,pii>
template<typename T> bool chmax(T& a, const T& b) { if (a < b) { a = b; return 1; } return 0; }
template<typename T> bool chmin(T& a, const T& b) { if (a > b) { a = b; return 1; } return 0; }
#define all(v) (v).begin(),(v).end()
#define bit(i) (1LL<<(i))
#define test(b, i) (((b) >> i) & 1)

struct LowLink{
private:
    vector<vector<int>> G;
    int cnt = 0;
    vector<bool> _is_art;

    void DFS(int v, int p=-1){
        low[v] = ord[v] = ++cnt;
        int n_ch = 0;
        for(int u : G[v])if(u != p){
            if(ord[u] == 0){
                DFS(u, v);
                low[v] = min(low[v], low[u]);
                n_ch++;
                if(p != -1 && ord[v] <= low[u])_is_art[v] = true;
            }
            else low[v] = min(low[v], ord[u]);
        }

        if(p == -1 && n_ch >= 2)_is_art[v] = true;

        return;
    }

public:
    vector<int> ord, low;

    LowLink(int N){
        G.resize(N + 1);
        _is_art.resize(N + 1);
        ord.resize(N + 1);
        low.resize(N + 1);
        return;
    }

    void add_edge(int a, int b){
        if(G.size() < max(a, b) + 1){
            G.resize(max(a, b) + 1);
            _is_art.resize(max(a, b) + 1);
            ord.resize(max(a, b) + 1);
            low.resize(max(a, b) + 1);
        }

        G[a].push_back(b);
        G[b].push_back(a);

        return;
    }

    void build(){
        for(int v = 0; v < G.size(); v++)if(ord[v] == 0){
            DFS(v);
        }

        return;
    }

    bool is_art(int n){ return _is_art[n]; }

    bool is_edge(int a, int b){
        if(ord[a] > ord[b])swap(a, b);
        return ord[a] < low[b];
    }

    bool is_edge(pair<int,int> e){
        return is_edge(e.first, e.second);
    }
};

const int MAXN = 1e5 + 10;
const int MAXM = 1e5 + 10;

int N, M;
vector<pii> E;

signed main(){
    cin >> N >> M;
    LowLink ll(N);
    rep(i, M){
        int a, b;
        cin >> a >> b;
        E.push_back({a, b});
        ll.add_edge(a, b);
    }

    ll.build();

    set<pii> ans;
    rep(i, M){
        auto [a, b] = E[i];
        if(a > b)swap(a, b);
        if(ll.is_edge(a, b))ans.insert({a, b});
    }

    for(auto [a, b] : ans)cout << a << " " << b << endl;

    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 6396
final_rank: 13

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define int long long
const int INF = (1 << 30);


vector<int> prenum, parent, lowest;
vector<vector<int>> g;
vector<bool> visited;
int v, e, t;

void dfs(int u, int p) {
    prenum[u] = lowest[u] = t;
    t++;
    visited[u] = true;

    for(auto &&_v: g[u]) {
        if (!visited[_v]) {
            parent[_v] = u;
            dfs(_v, u);
            lowest[u] = min(lowest[u], lowest[_v]);
        }
        else if (_v != p) lowest[u] = min(lowest[u], prenum[_v]);
    }
}

void art_points() {
    t = 1;
    dfs(0, -1);

    set<int> ap;
    int nc = 0;
    for (int u = 1; u < v; u++)
    {
        int p = parent[u];
        if (p == 0) nc++;
        else if (prenum[p] <= lowest[u]) ap.insert(p);
    }
    if (nc > 1) {
        ap.insert(0);
    }
    for(auto &&x: ap) {
        cout << x << endl;
    }
}

void bridges() {
    t = 1;
    dfs(0, -1);

    set<pair<int, int>> bs;
    for (int u = 1; u < v; u++)
    {
        if (lowest[u] == prenum[u]) bs.insert({min(u, parent[u]), max(u, parent[u])});
    }
    for(auto &&x: bs) {
        cout << x.first << " " << x.second << endl;
    }
}

signed main() {
    cin >> v >> e;
    g.assign(v, vector<int> ());
    prenum.assign(v, INF);
    parent.assign(v, -1);
    lowest.assign(v, INF);
    visited.assign(v, false);
    for (int i = 0; i < e; i++)
    {
        int s, t;
        cin >> s >> t;
        g[s].push_back(t);
        g[t].push_back(s);
    }
    bridges();
}
accuracy: 1
time_ms: 10
memory_kb: 5428
final_rank: 8

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>

std::vector<std::vector<int>> G;
std::vector<bool> visited;
std::vector<int> prenum;
std::vector<int> lowest;
std::vector<int> parent;
int t = 1;

struct edge{
  int u, w;

  bool operator==(const edge& other) const {
    return u == other.u && w == other.w;
  }
};

void dfs(int u, int p){
  prenum[u] = lowest[u] = t;
  t++;
  visited[u] = true;

  for(int v : G[u]){
    if(!visited[v]){
      parent[v] = u;
      dfs(v, u);
      lowest[u] = std::min(lowest[u], lowest[v]);
    }else if(v != p){
      lowest[u] = std::min(lowest[u], prenum[v]);
    }
  }
}

void bridges(int v){
  t = 1;
  dfs(0, -1);

  std::vector<edge> bridges;
  for(int u=1; u<v; u++){
    if(lowest[u] == prenum[u]){
      edge tmp;
      tmp.u = std::min(u, parent[u]);
      tmp.w = std::max(u, parent[u]);
      bridges.push_back(tmp);
    }
  }
  
  std::sort(bridges.begin(), bridges.end(), [](const edge& a, const edge& b){
    if(a.u != b.u) return a.u < b.u;
    return a.w < b.w;
  });
  bridges.erase(std::unique(bridges.begin(), bridges.end()), bridges.end());
  for(edge x : bridges){
    std::cout << x.u << " " << x.w << std::endl;
  }
}

int main(){
  int v, e;
  std::cin >> v >> e;

  G.resize(v);
  visited.resize(v, false);
  prenum.resize(v, 0);
  lowest.resize(v, 0);
  parent.resize(v, 0);
  
  for(int i=0;i<e;i++){
    int u,w;
    std::cin >> u >> w;
    G[u].push_back(w);
    G[w].push_back(u);
  }

  bridges(v);
  
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 4728
final_rank: 3

code_snippet: #include<iostream>
#include<algorithm>
#include<vector>
#include<utility>
using namespace std;
#define loop(a,b) for (int a = 0;a < b;a++)
#define rep(a,b,c) for(int a = b;a < c;a++)
#define vec(a) vector<a>



struct edge{
    int s,t;
    edge(int s,int t){
        this->s = s;
        this->t = t;
        if(s > t) swap(this->s,this->t);
    }
    bool operator<(const edge& e) const{
        return s < e.s || (s == e.s && t < e.t);
    }

};

struct GRL_3_B{
    int n;
    vec(int) parent, prenum, lowest;
    vec(bool) visited;
    vec(edge) bridges;
    vec(vec(int)) G;

    GRL_3_B(int n):n(n),parent(n),prenum(n),lowest(n),G(n),visited(n,false){}

    void add_edge(int s,int t){
        G[s].push_back(t);
        G[t].push_back(s);
    }

    void dfs(int u,int& time,int p){
        prenum[u] = time++;
        lowest[u] = prenum[u];
        visited[u] = true;
        for(int v:G[u]){
            if(!visited[v]){
                parent[v] = u;
                dfs(v,time,u);
                lowest[u] = min(lowest[u], lowest[v]);
            }else if(v != p){
                lowest[u] = min(lowest[u],prenum[v]);
            }
        }
    }
    
    void get_bridges()
    {
        int time = 1;
        dfs(0,time,-1);
        rep(i,1,n){
            int p = parent[i];
            
            if(prenum[p] < lowest[i]){
                bridges.push_back(edge(p,i));
            }
        }
        sort(bridges.begin(),bridges.end());
        for(edge e:bridges) cout << e.s << " " << e.t << endl;
    }
};

int main(){
    int n,m;
    cin >> n >> m;
    GRL_3_B grl(n);
    loop(i,m){
        int s,t;
        cin >> s >> t;
        grl.add_edge(s,t);
    }
    grl.get_bridges();
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 5120
final_rank: 7

code_snippet: // GRL_3_B
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;

using Graph = vector<vector<int>>;

Graph G;
vector<bool> seen;
vector<int> prenum, parent, lowest;
int t;

void DFS(int u, int p) {
    prenum[u] = lowest[u] = t;
    t++;
    seen[u] = true;

    for(auto& v : G[u]) {
        if(!seen[v]) {
            parent[v] = u;
            DFS(v, u);
            lowest[u] = min(lowest[u], lowest[v]);
        }
        else if(v != p) {
            lowest[u] = min(lowest[u], prenum[v]);
        }
    }
}

void bridges(int v) {
    t = 1;
    DFS(0, -1);

    vector<pair<int, int>> bridge;
    for(int u=1; u<v; ++u) {
        if(lowest[u] == prenum[u]) {
            int a = parent[u];
            int b = u;
            if(a > b) swap(a, b);
            bridge.emplace_back(a, b);
        }
    }
    sort(bridge.begin(), bridge.end());
    for(auto& [a, b] : bridge) {
        cout << a << " " << b << endl;
    }
}

int main() {
    int v, e;
    cin >> v >> e;


    G.resize(v);
    seen.assign(v, false);
    prenum.resize(v);
    parent.resize(v, -1);
    lowest.resize(v);

    for(int i=0; i<e; ++i) {
        int s, t;
        cin >> s >> t;
        G[s].push_back(t);
        G[t].push_back(s);
    }

    bridges(v);
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 4628
final_rank: 1

code_snippet: #include <bits/stdc++.h>

using namespace std;
using ll = long long;
#define rep(i, n) for (int i = 0; (i) < (n); ++(i))

vector<int> adjList[100010];

int prenum[100010];
int lowest[100010];
int parent[100010];
bool visited[100010];

int t, V, E;
void dfs(int, int);

void Articulation_Points()
{

    t = 1;
    dfs(0, -1);
    vector<int> art_points;
    int nc = 0;

    for (int u = 1; u < V; u++)
    {
        int p = parent[u];
        if (p == 0)
        {
            nc++;
        }
        else if (prenum[p] <= lowest[u])
        {
            art_points.push_back(p);
        }
    }
    if (nc > 1)
    {
        art_points.push_back(0);
    }
    sort(art_points.begin(), art_points.end());
    art_points.erase(unique(art_points.begin(), art_points.end()), art_points.end());

    rep(i, art_points.size())
    {
        cout << art_points[i] << endl;
    }
}

void dfs(int u, int p)
{
    prenum[u] = lowest[u] = t;
    t++;
    visited[u] = true;

    for (int v : adjList[u])
    {
        if (!visited[v])
        {
            parent[v] = u;
            dfs(v, u);
            lowest[u] = min(lowest[u], lowest[v]);
        }
        else if (v != p)
        {
            lowest[u] = min(lowest[u], prenum[v]);
        }
    }
}

void find_bridge()
{
    t = 1;
    dfs(0, -1);

    vector<pair<int, int>> bridges_edge;
    for (int u = 1; u < V; u++)
    {
        if (lowest[u] == prenum[u])
        {
            if (parent[u] < u)
            {
                bridges_edge.push_back({parent[u], u});
            }else {
                bridges_edge.push_back({u, parent[u]});
            }
        }
    }
    sort(bridges_edge.begin(), bridges_edge.end());
    
    rep(i, bridges_edge.size())
    {
        cout << bridges_edge[i].first << " " << bridges_edge[i].second << endl;
    }
}

int main()
{

    cin >> V >> E;

    rep(i, E)
    {
        int s, t;
        cin >> s >> t;
        adjList[s].push_back(t);
        adjList[t].push_back(s);
    }
    find_bridge();
}
accuracy: 1
time_ms: 10
memory_kb: 7144
final_rank: 14

code_snippet: #include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

//Global Variable
vector<int> prenum;
vector<int> visited;
vector<int> parent;
//visited value 0=False, 1=True
int t; 
vector<int> lowest;
vector<vector<int>> G;
//G is graph vector

struct Edge{
    int s;
    int t;

    bool operator<(const Edge& other) const {
        if (s != other.s) return s < other.s;
        return t < other.t;
    }

    // 重複削除（unique用）：s と t が両方等しい場合
    bool operator==(const Edge& other) const {
        return s == other.s && t == other.t;
    }
};

void dfs(int u,int p){
    prenum[u] = t;
    lowest[u] = t;
    t = t + 1;
    visited[u] = 1;

    for(int i=0;i<G[u].size();i++){
        int v = G[u][i];
        if(!visited[v]){
            parent[v] = u;
            dfs(v,u);
            lowest[u] = min(lowest[u],lowest[v]);
        }else if(v!=p){
            lowest[u] = min(lowest[u],prenum[v]);
        }
    }
    return;
}

void bridges(int V){
    vector<Edge> bridges;
    Edge e;

    t = 1;
    dfs(0,-1);
    for(int u=1;u<V;u++){
        if(lowest[u]==prenum[u]){
            if(u<parent[u]){
                e.s = u;
                e.t = parent[u];
                bridges.push_back(e);
            }else{
                e.s = parent[u];
                e.t = u;
                bridges.push_back(e);
            }
        }
    }

    sort(bridges.begin(),bridges.end());
    bridges.erase(unique(bridges.begin(),bridges.end()), bridges.end());

    for(int i=0;i<bridges.size();i++){
        cout << bridges[i].s << " " << bridges[i].t << endl;
    }

    return;
}

int main(){
    int V,E;
    int s,t;

    cin >> V >> E;

    G.resize(V);

    for(int i=0;i<E;i++){
        cin >> s >> t;
        G[s].push_back(t);
        G[t].push_back(s);
    }

    for(int i=0;i<V;i++){
        prenum.push_back(0);
        visited.push_back(0);
        parent.push_back(0);
        lowest.push_back(0);
    }

    bridges(V);

    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 4720
final_rank: 2

code_snippet: #include <bits/stdc++.h>
#define INF 0x7fffffff
#define MAXN 200010
typedef long long LL;
using namespace std;

struct edge
{
	int u, v;
};

int n, m, cnt;
vector <int> g[MAXN];
int dfn[MAXN], low[MAXN];
vector <edge> ans;

void Tarjan(int u, int parent)
{
	low[u] = dfn[u] = ++cnt;
	for(int x = 0; x < g[u].size(); x++)
	{
		int v = g[u][x];
		if(v == parent) continue;
		if(!dfn[v])
		{
			Tarjan(v, u);
			low[u] = min(low[u], low[v]);
			if(low[v] > dfn[u]) ans.push_back((edge){min(u,v), max(u,v)});
		}
		else low[u] = min(low[u], dfn[v]);
	}
}

bool cmp(edge x, edge y)
{
	if(x.u == y.u) return x.v < y.v;
	return x.u < y.u;
}

vector <edge> getBridge()
{
	for(int x = 0; x < n; x++)
		if(!dfn[x]) Tarjan(x, -1);
	sort(ans.begin(), ans.end(), cmp);
	return ans;
}

int main()
{
	cin >> n >> m;
	for(int x = 1; x <= m; x++)
	{
		int u, v;
		cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	vector <edge> B = getBridge();
	for(int x = 0; x < B.size(); x++) cout << B[x].u << " " << B[x].v << endl;
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 9712
final_rank: 19

code_snippet: //0 points && ik that but i'll have a try..
#include <bits/stdc++.h>
#define ll long long
#define db double
#define ld long double
#define endl '\n'
#define eb emplace_back
#define em emplace
#define pb push_back
#define pf push_front
#define pp pop_back
#define fr first
#define sc second
#define sz size
using namespace std;
const ll mx = 100005;
vector<ll> g[mx] ;
vector<pair<ll, ll>> res;
ll in[mx] , lw[mx] ,t ;
bool vs[mx] ;
void dfs(ll u , ll p = -1) {
    vs[u] = true;
    in[u] = lw[u] = t++ ;
    for (ll v : g[u]) {
        if (v == p) continue;
        if (vs[v]) lw[u] = min(lw[u] , in[v]);
        else {
            dfs(v, u);
            lw[u] = min(lw[u] , lw[v]);
            if (lw[v] > in[u]) res.eb(min(u ,v) , max(u , v));
        }
    }
}
signed main() {
    ll n , m ;
    cin >> n >> m ;
    while (m--) {
        ll u , v ;
        cin >> u >> v ;
        g[u].pb(v) ;
        g[v].pb(u) ;
    }
    for (ll i = 0 ; i < n ; i++) if (!vs[i]) dfs(i) ;
    sort(res.begin(), res.end());
    for (auto &x : res) cout << x.fr << " " << x.sc << endl;
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 7852
final_rank: 15

code_snippet: //#pragma GCC target("avx2")
//#pragma GCC optimize("O3")
//#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
using pli = pair<ll,int>;
void inline TEST(void){cerr << "TEST" << endl;}
#define AMARI 998244353
//#define AMARI 1000000007
#define el '\n'
#define El '\n'
#define YESNO(x) ((x) ? "Yes" : "No")
#define YES YESNO(true)
#define NO YESNO(false)
#define REV_PRIORITY_QUEUE(tp) priority_queue<tp,vector<tp>,greater<tp>>
#define NO_ANS(x) {cout << (x) << '\n'; return;}
template <typename T>
void inline VEC_UNIQ(vector<T> &v){
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    return;
}


//lowlink
//このライブラリでは無向グラフにしか対応していないが、本来は有向グラフでもできるらしい。
class ococo_lowlink{
    private:
        int n;
        int cnt = 0;
        vector<vector<int>> g;
        vector<int> ord,low,par,depth;
        vector<vector<int>> depth_inv;
        vector<bool> kansetuten;
        void dfs(int p,int v){
            par[v] = p;
            low[v] = ord[v] = cnt;
            cnt++;
            for(int i = 0; i < (int)g[v].size(); i++){
                int to = g[v][i];
                if(to == p)continue;
                if(ord[to] == -1){
                    depth[to] = depth[v] + 1;
                    depth_inv[depth[to]].push_back(to);
                    dfs(v,to);
                    low[v] = min(low[v],low[to]);
                }
                else low[v] = min(low[v],ord[to]);
            }
        }
        public:
        ococo_lowlink(int N = 0){
            n = N;
            g.resize(n);
            ord.resize(n);
            low.resize(n);
            par.resize(n);
            depth.resize(n);
            depth_inv.resize(n);
            kansetuten.resize(n);
            for(int i = 0; i < n; i++)depth_inv[i].clear();
        }
        void einsert(int u,int v){
            g[u].push_back(v);
            g[v].push_back(u);
        }
        void peinsert(pair<int,int> p){
            einsert(p.first,p.second);
        }
        void build(void){
            //cerr << (int)depth.size() << ' ' << (int)depth_inv.size() << el;
            cnt = 0;
            for(int i = 0; i < n; i++)ord[i] = -1;
            for(int i = 0; i < n; i++){
                if(ord[i] == -1){
                    depth[i] = 0;
                    depth_inv[i].push_back(0);
                    dfs(-1,i);
                }
            }
            for(int i = n - 1; i >= 0; i--){
                for(int j = 0; j < depth_inv[i].size(); j++){
                    int fr = depth_inv[i][j];
                    for(int l = 0; l < g[fr].size(); l++){
                        int to = g[fr][l];
                        if(to == par[fr])continue;
                        //low[fr] = min(low[to],low[fr]);
                    }
                }
            }
            for(int i = 0; i < n; i++){
                int bc = 0;
                for(int j = 0; j < (int)g[i].size(); j++){
                    int to = g[i][j];
                    if(par[to] != i)continue;
                    if(ord[i] <= low[to])bc++;
                }
                if(i == 0 && bc >= 2)kansetuten[i] = true;
                if(i >= 1 && bc >= 1)kansetuten[i] = true;
            }
        }
        bool is_bridge(int u,int v){
            if(par[v] != u)swap(u,v);
            //いま、vの親がu
            if(low[v] > ord[u])return true;
            return false;
        }
        bool is_kansetuten(int v){
            return kansetuten[v];
        }
    
        //DFS 順でその頂点に辿り着いたのが何個目の頂点かを持つ配列 order を返す
        vector<int> get_order(void){
            return ord;
        }
    
        //DFS木上の辺を親→子の方向に好きな回数、後退辺(DFS 木上にない辺)を1回以下通って到達可能な order の最小値を返す。
        //↑この説明は有向グラフだと間違いらしい。
        //order[u] < order[v] としたとき、order[u] < low[v] であることと辺 (u,v) が橋であることが同値であることを利用して、lowlink は動いている。（らしい）
        //（橋でないなら (u,v）間に後退辺がないから、low[v] >= order[u] になる）
        vector<int> get_low(void){
            return low;
        }
    };
    
#define MULTI_TEST_CASE false
void solve(void){
    //問題を見たらまず「この問題設定から言えること」をいっぱい言う
    //一個回答に繋がりそうな解法が見えても、実装や細かい詰めに時間がかかりそうなら別の方針を考えてみる
    //ある程度考察しても全然取っ掛かりが見えないときは実験をしてみる
    //よりシンプルな問題に言い換えられたら、言い換えた先の問題を自然言語ではっきりと書く
    //複数の解法のアイデアを思いついた時は全部メモしておく
    //g++ -D_GLIBCXX_DEBUG -Wall -O2 XXX.cpp -o o

    int n,m;
    cin >> n >> m;
    ococo_lowlink llink(n);
    vector<pii> edge;
    while(m--){
        int u,v;
        cin >> u >> v;
        if(u > v)swap(u,v);
        llink.einsert(u,v);
        edge.push_back(pair(u,v));
    }
    llink.build();
    sort(edge.begin(),edge.end());

    for(int i = 0; i < (int)edge.size(); i++){
        if(llink.is_bridge(edge[i].first,edge[i].second)){
            cout << edge[i].first << ' ' << edge[i].second << el;
        }
    }

    return;
}

void calc(void){
    return;
}

signed main(void){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    calc();
    int t = 1;
    if(MULTI_TEST_CASE)cin >> t;
    while(t--){
        solve();
    }
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 5624
final_rank: 9

code_snippet: #include <bits/stdc++.h>
using namespace std;

vector<vector<int>> G;
vector<int> disc, low;
vector<pair<int, int>> bridges;
int tt;

void dfs(int u, int parent) {
	disc[u] = low[u] = ++tt;
	for (int v : G[u]) {
		if (disc[v] == 0) {
			dfs(v, u);
			low[u] = min(low[u], low[v]);
			if (low[v] > disc[u]) {
				if (u < v) bridges.push_back({u, v});
				else bridges.push_back({v, u});
			}
		} else if (v != parent) 
			low[u] = min(low[u], disc[v]);
	}
}

int main() {
	int V, E;
	cin >> V >> E;
	G.resize(V);
	while (E--) {
		int s, t;
		cin >> s >> t;
		G[s].push_back(t);
		G[t].push_back(s);
	}
	
	disc.assign(V, 0);
	low.resize(V);
	dfs(0, -1);
	sort(bridges.begin(), bridges.end());
	
	for (auto& bridge : bridges) {
		cout << bridge.first << " " << bridge.second << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 5020
final_rank: 6

code_snippet: #line 1 "verify/AOJ-GRL-3-B.test.cpp"
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/courses/library/5/GRL/3/GRL_3_B"

#line 2 "Library/Template.hpp"

/**
 * @file Template.hpp
 * @author log K (lX57)
 * @brief Template - テンプレート
 * @version 1.10
 * @date 2025-03-16
 */

#line 2 "Library/Common.hpp"

/**
 * @file Common.hpp
 */

#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <cstdint>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
using namespace std;

using ll = int64_t;
using ull = uint64_t;

constexpr const ll INF = (1LL << 62) - (1LL << 30) - 1;
#line 12 "Library/Template.hpp"

inline bool YnPrint(bool flag){cout << (flag ? "Yes" : "No") << '\n'; return flag;}
inline bool YNPrint(bool flag){cout << (flag ? "YES" : "NO") << '\n'; return flag;}
template<typename Container>
inline void Sort(Container &container){sort(container.begin(), container.end());}
template<typename Container>
inline void ReverseSort(Container &container){sort(container.rbegin(), container.rend());}
template<typename Container>
inline void Reverse(Container &container){reverse(container.begin(), container.end());}
template<typename Value>
inline int PopCount(const Value &value){return __builtin_popcount(value);}
template<typename Value>
inline Value Ceil(const Value &numerator, const Value &denominator){return (numerator + denominator - 1) / denominator;}
template<typename Value>
inline int LowerBoundIndex(const vector<Value> &container, const Value &value){return distance(container.begin(), lower_bound(container.begin(), container.end(), value));}
template<typename Value>
inline int UpperBoundIndex(const vector<Value> &container, const Value &value){return distance(container.begin(), upper_bound(container.begin(), container.end(), value));}
template<typename Value>
inline bool Between(const Value &lower, const Value &x, const Value &higher){return lower <= x && x <= higher;}
template<typename Value>
inline bool InGrid(const Value &y, const Value &x, const Value &ymax, const Value &xmax){return Between(0, y, ymax - 1) && Between(0, x, xmax - 1);}
template<typename Value>
inline Value Median(const Value &a, const Value &b, const Value &c){return Between(b, a, c) || Between(c, a, b) ? a : (Between(a, b, c) || Between(c, b, a) ? b : c);}
template<typename Value>
inline Value Except(Value &src, Value &cond, Value &excp){return (src == cond ? excp : src);}

template<class Value>
bool chmin(Value &src, const Value &cmp){if(src > cmp){src = cmp; return true;} return false;}
template<class Value>
bool chmax(Value &src, const Value &cmp){if(src < cmp){src = cmp; return true;} return false;}
template<typename Value>
inline Value min(vector<Value> &v){return *min_element((v).begin(), (v).end());}
template<typename Value>
inline Value max(vector<Value> &v){return *max_element((v).begin(), (v).end());}

const int dx4[4] = {1, 0, -1, 0};
const int dy4[4] = {0, -1, 0, 1};
const int dx8[8] = {1, 1, 0, -1, -1, -1, 0, 1};
const int dy8[8] = {0, -1, -1, -1, 0, 1, 1, 1};

vector<pair<int, int>> adjacent(int current_y, int current_x, int max_y, int max_x, bool dir_8 = false){
    vector<pair<int, int>> ret;
    for(int d = 0; d < 4 * (1 + dir_8); ++d){
        int next_y = current_y + (dir_8 ? dy8[d] : dy4[d]);
        int next_x = current_x + (dir_8 ? dx8[d] : dx4[d]);
        if(InGrid(next_y, next_x, max_y, max_x)){
            ret.emplace_back(next_y, next_x);
        }
    }
    return ret;
}

template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p){
    os << p.first << " " << p.second;
    return os;
}

template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &p){
    is >> p.first >> p.second;
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, vector<T> &v){
    for (int i = 0; i < v.size(); ++i){
        os << v[i] << (i + 1 != v.size() ? " " : "");
    }
    return os;
}

template <typename T>
ostream &operator<<(ostream &os, vector<vector<T>> &v){
    for (int i = 0; i < v.size(); ++i){
        os << v[i] << (i + 1 != v.size() ? "\n" : "");
    }
    return os;
}

template <typename T>
istream &operator>>(istream &is, vector<T> &v){
    for (int i = 0; i < v.size(); ++i) is >> v[i];
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, set<T> &v){
    for (auto &u : v){
        os << u << " ";
    }
    return os;
}

template<typename T1, typename T2>
vector<pair<T1, T2>> AssembleVectorPair(vector<T1> &v1, vector<T2> &v2){
    assert(v1.size() == v2.size());
    vector<pair<T1, T2>> v;
    for(int i = 0; i < v1.size(); ++i) v.push_back({v1[i], v2[i]});
    return v;
}

template<typename T1, typename T2>
pair<vector<T1>, vector<T2>> DisassembleVectorPair(vector<pair<T1, T2>> &v){
    vector<T1> v1;
    vector<T2> v2;
    transform(v.begin(), v.end(), back_inserter(v1), [](auto p){return p.first;});
    transform(v.begin(), v.end(), back_inserter(v2), [](auto p){return p.second;});
    return {v1, v2};
}

template<typename T1, typename T2, typename T3>
tuple<vector<T1>, vector<T2>, vector<T3>> DisassembleVectorTuple(vector<tuple<T1, T2, T3>> &v){
    vector<T1> v1;
    vector<T2> v2;
    vector<T3> v3;
    transform(v.begin(), v.end(), back_inserter(v1), [](auto p){return get<0>(p);});
    transform(v.begin(), v.end(), back_inserter(v2), [](auto p){return get<1>(p);});
    transform(v.begin(), v.end(), back_inserter(v3), [](auto p){return get<2>(p);});
    return {v1, v2, v3};
}

template<typename T1 = int, typename T2 = T1>
pair<vector<T1>, vector<T2>> InputVectorPair(int size){
    vector<pair<T1, T2>> v(size);
    for(auto &[p, q] : v) cin >> p >> q;
    return DisassembleVectorPair(v);
}

template<typename T1 = int, typename T2 = T1, typename T3 = T1>
tuple<vector<T1>, vector<T2>, vector<T3>> InputVectorTuple(int size){
    vector<tuple<T1, T2, T3>> v(size);
    for(auto &[p, q, r] : v) cin >> p >> q >> r;
    return DisassembleVectorTuple(v);
}
#line 2 "Library/Graph/LowLink.hpp"

#line 2 "Library/Graph/Graph.hpp"

#line 4 "Library/Graph/Graph.hpp"

using Vertex = int;

template<typename CostType = int32_t>
struct Edge{
    public:
    Edge() = default;

    Edge(Vertex from_, Vertex to_, CostType cost_ = 1, int idx_ = -1) :
        from(from_), to(to_), cost(cost_), idx(idx_){}
    
    bool operator<(const Edge<CostType> &e) const {return cost < e.cost;}

    operator int() const {return to;}

    Vertex from, to;
    CostType cost;
    int idx;
};

template<typename CostType = int32_t>
class Graph{
    public:
    Graph() = default;

    Graph(int n) : vertex_size_(n), edge_size_(0), adjacent_list_(n){}
    
    inline void AddUndirectedEdge(Vertex u, Vertex v, CostType w = 1){
        int idx = edge_size_++;
        adjacent_list_[u].push_back(Edge<CostType>(u, v, w, idx));
        adjacent_list_[v].push_back(Edge<CostType>(v, u, w, idx));
    }
    
    inline void AddDirectedEdge(Vertex u, Vertex v, CostType w = 1){
        int idx = edge_size_++;
        adjacent_list_[u].push_back(Edge<CostType>(u, v, w, idx));
    }

    inline size_t VertexSize() const {
        return vertex_size_;
    }

    inline size_t EdgeSize() const {
        return edge_size_;
    }

    inline vector<Edge<CostType>> &operator[](const int v){
        return adjacent_list_[v];
    }

    inline const vector<Edge<CostType>> &operator[](const int v) const {
        return adjacent_list_[v];
    }
    
    private:
    size_t vertex_size_, edge_size_;
    vector<vector<Edge<CostType>>> adjacent_list_;
};

template<typename CostType = int32_t>
Graph<CostType> InputGraph(int N, int M, int padding = -1, bool weighted = false, bool directed = false){
    Graph<CostType> G(N);
    for(int i = 0; i < M; ++i){
        Vertex u, v; CostType w = 1;
        cin >> u >> v, u += padding, v += padding;
        if(weighted) cin >> w;
        if(directed) G.AddDirectedEdge(u, v, w);
        else G.AddUndirectedEdge(u, v, w);
    }
    return G;
}
#line 4 "Library/Graph/LowLink.hpp"

template<typename CostType>
class LowLink{
    public:
    LowLink(Graph<CostType> &graph) : G(graph), n(graph.VertexSize()), ord_(n, -1), low_(n, -1), in_(n), out_(n){
        for(int i = 0, k = 0, t = 0; i < n; ++i){
            if(ord_[i] == -1){
                k = dfs(i, -1, k, t);
            }
        }
    }

    vector<Vertex> &ArticulationVertex(){
        return articulation_vertex_;
    }

    vector<pair<Vertex, Vertex>> &Bridge(){
        return bridge_;
    }

    pair<int, int> EulerTour(const Vertex v) const {
        return {in_[v], out_[v]};
    }

    private:
    Graph<CostType> &G;
    int n;
    vector<int> ord_, low_, in_, out_;
    vector<Vertex> articulation_vertex_;
    vector<pair<Vertex, Vertex>> bridge_;

    int dfs(Vertex v, int p, int k, int &t){
        in_[v] = t++;
        low_[v] = (ord_[v] = k++);
        int cnt = 0;
        bool is_articulation = false, second = false;
        for(int u : G[v]){
            if(ord_[u] == -1){
                ++cnt;
                k = dfs(u, v, k, t);
                low_[v] = min(low_[v], low_[u]);
                is_articulation |= (p != -1) && (low_[u] >= ord_[v]);
                if(ord_[v] < low_[u]){
                    bridge_.emplace_back(minmax(u, v));
                }
            }
            else if(u != p || second){
                low_[v] = min(low_[v], ord_[u]);
            }
            else{
                second = true;
            }
        }
        is_articulation |= (p == -1) && (cnt > 1);
        if(is_articulation) articulation_vertex_.emplace_back(v);
        out_[v] = t;
        return k;
    }
};
#line 5 "verify/AOJ-GRL-3-B.test.cpp"

int main(){
    int V, E; cin >> V >> E;
    auto G = InputGraph<ll>(V, E, 0, false, false);
    
    LowLink llk(G);
    auto ans = llk.Bridge();
    Sort(ans);
    for(const auto [s, t] : ans) cout << s << ' ' << t << '\n';
}
accuracy: 1
time_ms: 10
memory_kb: 8140
final_rank: 16

code_snippet: #line 1 "verify/AOJ-GRL-3-B.test.cpp"
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/courses/library/5/GRL/1/GRL_3_B"

#line 2 "Library/Template.hpp"

/**
 * @file Template.hpp
 * @author log K (lX57)
 * @brief Template - テンプレート
 * @version 1.9
 * @date 2024-10-27
 */

#line 2 "Library/Common.hpp"

/**
 * @file Common.hpp
 */

#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <cstdint>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
#line 12 "Library/Template.hpp"
#define ALL(x) (x).begin(), (x).end()
#define RALL(x) (x).rbegin(), (x).rend()
#define SORT(x) sort(ALL(x))
#define RSORT(x) sort(RALL(x))
#define REVERSE(x) reverse(ALL(x))
#define SETPRE(digit) fixed << setprecision(digit)
#define POPCOUNT(x) __builtin_popcount(x)
#define SUM(x) reduce((x).begin(), (x).end())
#define CEIL(nume, deno) ((nume) + (deno) - 1) / (deno)
#define IOTA(x) iota((x).begin(), (x).end(), 0)
#define LOWERBOUND_IDX(arr, val) distance((arr).begin(), lower_bound((arr).begin(), (arr).end(), val))
#define UPPERBOUND_IDX(arr, val) distance((arr).begin(), upper_bound((arr).begin(), (arr).end(), val))

inline string Yn(bool flag){return (flag) ? "Yes" : "No";}
inline bool YnPrint(bool flag){cout << Yn(flag) << endl;return flag;}
inline string YN(bool flag){return (flag) ? "YES" : "NO";}
inline bool YNPrint(bool flag){cout << YN(flag) << endl;return flag;}
template<class T>
bool chmin(T &src, const T &cmp){if(src > cmp){src = cmp; return true;}return false;}
template<class T>
bool chmax(T &src, const T &cmp){if(src < cmp){src = cmp; return true;}return false;}
template<typename T>
inline bool between(T min, T x, T max){return min <= x && x <= max;}
template<typename T>
inline bool ingrid(T y, T x, T ymax, T xmax){return between(0, y, ymax - 1) && between(0, x, xmax - 1);}
template<typename T>
inline T median(T a, T b, T c){return between(b, a, c) || between(c, a, b) ? a : (between(a, b, c) || between(c, b, a) ? b : c);}
template<typename T>
inline T except(T src, T cond, T excp){return (src == cond ? excp : src);}
template<typename T>
inline T min(vector<T> &v){return *min_element((v).begin(), (v).end());}
template<typename T>
inline T max(vector<T> &v){return *max_element((v).begin(), (v).end());}
vector<int> make_sequence(int Size){
    vector<int> ret(Size);
    IOTA(ret);
    return ret;
}
template<typename T>
void make_unique(vector<T> &v){
    sort(v.begin(), v.end());
    auto itr = unique(v.begin(), v.end());
    v.erase(itr, v.end());
}

using ll = int64_t;
using ull = uint64_t;
using ld = long double;

const int INF_INT = numeric_limits<int>::max() >> 2;
const ll INF_LL = numeric_limits<ll>::max() >> 2;

using vi = vector<int>;
using vvi = vector<vi>;
using vl = vector<ll>;
using vvl = vector<vl>;
using pi = pair<int, int>;
using pl = pair<ll, ll>;
using vs = vector<string>;
template <typename T>
using pq = priority_queue<T>;
template <typename T>
using rpq = priority_queue<T, vector<T>, greater<T>>;

const int dx4[4] = {1, 0, -1, 0};
const int dy4[4] = {0, -1, 0, 1};
const int dx8[8] = {1, 1, 0, -1, -1, -1, 0, 1};
const int dy8[8] = {0, -1, -1, -1, 0, 1, 1, 1};

vector<pair<int, int>> adjacent(int current_y, int current_x, int max_y, int max_x, bool dir_8 = false){
    vector<pair<int, int>> ret;
    for(int d = 0; d < 4 * (1 + dir_8); ++d){
        int next_y = current_y + (dir_8 ? dy8[d] : dy4[d]);
        int next_x = current_x + (dir_8 ? dx8[d] : dx4[d]);
        if(0 <= next_y and next_y < max_y and 0 <= next_x and next_x < max_x){
            ret.emplace_back(next_y, next_x);
        }
    }
    return ret;
}

template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p){
    os << p.first << ' ' << p.second;
    return os;
}

template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &p){
    is >> p.first >> p.second;
    return is;
}

template <typename T>
istream &operator>>(istream &is, vector<T> &v){
    for (int i = 0; i < v.size(); ++i) is >> v[i];
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, const vector<T> &v){
    os << v[0];
    for (int i = 1; i < v.size(); ++i){
        os << ' ' << v[i];
    }
    return os;
}

template <typename T>
ostream &operator<<(ostream &os, const vector<vector<T>> &v){
    os << v[0];
    for (int i = 0; i < v.size(); ++i){
        os << '\n' << v[i];
    }
    return os;
}

template<class T>
void Print(const T &a){
    cout << a << '\n';
}

template<class T, class... Ts>
void Print(const T &a, const Ts &...b){
    cout << a;
    (cout << ... << (cout << ' ', b));
    cout << '\n';
}

template<typename T1, typename T2>
vector<pair<T1, T2>> AssembleVectorPair(vector<T1> &v1, vector<T2> &v2){
    assert(v1.size() == v2.size());
    vector<pair<T1, T2>> v;
    for(int i = 0; i < v1.size(); ++i) v.push_back({v1[i], v2[i]});
    return v;
}

template<typename T1, typename T2>
pair<vector<T1>, vector<T2>> DisassembleVectorPair(vector<pair<T1, T2>> &v){
    vector<T1> v1;
    vector<T2> v2;
    transform(v.begin(), v.end(), back_inserter(v1), [](auto p){return p.first;});
    transform(v.begin(), v.end(), back_inserter(v2), [](auto p){return p.second;});
    return {v1, v2};
}

template<typename T1, typename T2, typename T3>
tuple<vector<T1>, vector<T2>, vector<T3>> DisassembleVectorTuple(vector<tuple<T1, T2, T3>> &v){
    vector<T1> v1;
    vector<T2> v2;
    vector<T3> v3;
    transform(v.begin(), v.end(), back_inserter(v1), [](auto p){return get<0>(p);});
    transform(v.begin(), v.end(), back_inserter(v2), [](auto p){return get<1>(p);});
    transform(v.begin(), v.end(), back_inserter(v3), [](auto p){return get<2>(p);});
    return {v1, v2, v3};
}

template<typename T1 = int, typename T2 = T1>
pair<vector<T1>, vector<T2>> InputVectorPair(int size){
    vector<pair<T1, T2>> v(size);
    for(auto &[p, q] : v) cin >> p >> q;
    return DisassembleVectorPair(v);
}

template<typename T1 = int, typename T2 = T1, typename T3 = T1>
tuple<vector<T1>, vector<T2>, vector<T3>> InputVectorTuple(int size){
    vector<tuple<T1, T2, T3>> v(size);
    for(auto &[p, q, r] : v) cin >> p >> q >> r;
    return DisassembleVectorTuple(v);
}

ll modpow(ll a, ll x, ll m){
    ll ret = 1, cur = a % m, rem = x;
    while(rem){
        if(rem & 1) ret = (ret * cur) % m;
        rem >>= 1, cur = (cur * cur) % m;
    }
    return ret;
}

#ifdef LOGK
#define VARIABLE(var) cerr << "# " << #var << " = " << var << endl;
#else
#define VARIABLE(...) 42
#endif
#line 2 "Library/Graph/LowLink.hpp"

#line 4 "Library/Graph/LowLink.hpp"

class LowLink{
    public:
    LowLink(size_t n) : n_(n), edges_(0), G(n), in_(n, -1), out_(n, -1), low_(n, -1){}

    void AddEdge(int u, int v, int id = -1){
        if(id == -1) id = edges_;
        G[u].emplace_back(v, id);
        G[v].emplace_back(u, id);
        ++edges_;
    }

    void Build(){
        for(int i = 0, t = 0; i < n_; ++i){
            if(in_[i] < 0) dfs(i, -1, t);
        }
    }

    bool IsBridge(int id){
        return bridge_.contains(id);
    }

    bool IsArticulation(int v){
        return articulation_.contains(v);
    }

    vector<int> GetBridge(){
        vector<int> ret;
        for(const auto &[id, _] : bridge_) ret.push_back(id);
        sort(ret.begin(), ret.end());
        return ret;
    }

    vector<int> GetArticulation(){
        vector<int> ret;
        for(const auto &[v, _] : articulation_) ret.push_back(v);
        sort(ret.begin(), ret.end());
        return ret;
    }

    private:
    void dfs(int u, int e, int &t){
        in_[u] = low_[u] = t++;
        int c = 0;
        for(const auto &[v, id] : G[u]){
            if(in_[v] < 0){
                dfs(v, id, t);
                low_[u] = min(low_[u], low_[v]);
                ++c;
                if(low_[v] > in_[u]) bridge_[id] = v;
                if(e != -1 && low_[v] >= in_[u]) articulation_[u] = v;
            }
            else if(id != e){
                low_[u] = min(low_[u], in_[v]);
            }
        }
        if(e == -1 && c >= 2) articulation_[u] = G[u].front().first;
        out_[u] = t;
    }

    size_t n_, edges_;
    vector<vector<pair<int, int>>> G;
    vector<int> in_, out_, low_;
    unordered_map<int, int> bridge_, articulation_;
};
#line 5 "verify/AOJ-GRL-3-B.test.cpp"

int main(){
    int V, E; cin >> V >> E;
    auto [s, t] = InputVectorPair<int>(E);
    
    LowLink lk(V);
    for(int i = 0; i < E; ++i){
        lk.AddEdge(s[i], t[i], i);
    }
    lk.Build();

    vector<pair<int, int>> ans;
    for(const auto &i : lk.GetBridge()){
        ans.emplace_back(min(s[i], t[i]), max(s[i], t[i]));
    }
    sort(ans.begin(), ans.end());
    for(const auto &[S, T] : ans){
        cout << S << ' ' << T << '\n';
    }
}
accuracy: 1
time_ms: 10
memory_kb: 6224
final_rank: 12

code_snippet: #include <bits/stdc++.h>

using namespace std;

class BridgeDetection {
  private:
    map<int, vector<int>> edges;
    int size;
    vector<int> ord;
    vector<int> low;
    vector<int> parent;
    vector<bool> visited;
    vector<pair<int, int>> bridges;

  public:
    BridgeDetection(int n) : size(n) {
        ord = vector<int>(n, -1);
        low = vector<int>(n, -1);
        parent = vector<int>(n, -1);
        visited = vector<bool>(n, false);
    }
    void add_edge(int u, int v) {
        edges[u].push_back(v);
        edges[v].push_back(u);
    }
    void dfs(int u, int time) {
        visited[u] = true;
        ord[u] = time;
        low[u] = time;

        for (auto v : edges[u]) {
            if (!visited[v]) {
                parent[v] = u;
                dfs(v, time + 1);

                low[u] = min(low[u], low[v]);
                if (low[v] > ord[u]) {
                    pair<int, int> p;
                    if (u < v) {
                        p.first = u;
                        p.second = v;
                    } else {
                        p.first = v;
                        p.second = u;
                    }
                    bridges.push_back(p);
                }
            } else if (v != parent[u]) {
                low[u] = min(low[u], ord[v]);
            }
        }
    }
    void exec() {
        for (int i = 0; i < size; ++i) {
            if (!visited[i]) {
                dfs(i, 0);
            }
        }
    }
    void print() {
        sort(bridges.begin(), bridges.end());
        for (auto p : bridges) {
            cout << p.first << " " << p.second << endl;
        }
    }
};
int main() {
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);

    int v, e;
    cin >> v >> e;
    BridgeDetection graph = BridgeDetection(v);
    for (int i = 0; i < e; ++i) {
        int s, t;
        cin >> s >> t;
        graph.add_edge(s, t);
    }
    graph.exec();
    graph.print();
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 5704
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;
//#include <atcoder/all>
//using namespace atcoder;
using ll=long long;
using ld=long double;
using uint=uint32_t;
using ull=uint64_t;
using pii=pair<int,int>;
using pll=pair<ll,ll>;
//using mint=modint998244353;
using graph=vector<vector<int>>;
const ll INF=1ll<<60;

struct Edge {
    int to;
};
using Graph = vector<vector<Edge>>;
using P = pair<long, long>;

/* Lowlink: グラフの関節点・橋を列挙する構造体
    作成: O(E+V)
    関節点の集合: vector<int> aps
    橋の集合: vector<P> bridges
*/
struct LowLink {
    const Graph &G;
    vector<int> used, ord, low;
    vector<int> aps;  // articulation points
    vector<P> bridges;

    LowLink(const Graph &G_) : G(G_) {
        used.assign(G.size(), 0);
        ord.assign(G.size(), 0);
        low.assign(G.size(), 0);
        int k = 0;
        for (int i = 0; i < (int)G.size(); i++) {
            if (!used[i]) k = dfs(i, k, -1);
        }
        sort(aps.begin(), aps.end()); // 必要ならソートする
        sort(bridges.begin(), bridges.end()); // 必要ならソートする
    }

    int dfs(int id, int k, int par) { // id:探索中の頂点, k:dfsで何番目に探索するか, par:idの親
        used[id] = true;
        ord[id] = k++;
        low[id] = ord[id];
        bool is_aps = false;
        int count = 0; // 子の数
        for (auto &e : G[id]) {
            if (!used[e.to]) {
                count++;
                k = dfs(e.to, k, id);
                low[id] = min(low[id], low[e.to]);
                if (par != -1 && ord[id] <= low[e.to]) is_aps = true; 
                if (ord[id] < low[e.to]) bridges.emplace_back(min(id, e.to), max(id, e.to)); // 条件を満たすので橋  
            } else if (e.to != par) { // eが後退辺の時
                low[id] = min(low[id], ord[e.to]);
            }
        }
        if (par == -1 && count >= 2) is_aps = true; 
        if (is_aps) aps.push_back(id);
        return k;
    }
};

int main(){
  int V,E; cin>>V>>E;
  Graph G(V);
  for(int i=0;i<E;i++){
    int u,v; cin>>u>>v;
    G[u].emplace_back(Edge{v});
    G[v].emplace_back(Edge{u});
  }
  LowLink L{G};
  for(P i:L.bridges){
    cout<<i.first<<" "<<i.second<<endl;
  }
}
accuracy: 1
time_ms: 10
memory_kb: 4904
final_rank: 5

code_snippet: ﻿// ### test.cpp ###
#include <bits/stdc++.h>
#ifdef __DEBUG_VECTOR
namespace for_debugging{
    struct subscript_and_location{
        int sub;
        std::source_location loc;
        subscript_and_location(int sub_,std::source_location loc_=std::source_location::current()){
            sub=sub_;
            loc=loc_;
        }
        void check_out_of_range(size_t sz){
            if(sub<0||(int)sz<=sub){
                std::clog << loc.file_name() << ":(" << loc.line() << ":" << loc.column() << "):" << loc.function_name() << std::endl;
                std::clog << "out of range: subscript = " << sub << ", vector_size = " << sz << std::endl;
                exit(EXIT_FAILURE);
            }
        }
    };
}
namespace std{
    template<class T,class Allocator=std::allocator<T>> class vector_for_debugging:public std::vector<T,Allocator>{
        using std::vector<T,Allocator>::vector;
        public:
            [[nodiscard]] constexpr std::vector<T,Allocator>::reference operator[](for_debugging::subscript_and_location n) noexcept(!std::is_same<T,bool>::value){
                n.check_out_of_range(this->size());
                return std::vector<T,Allocator>::operator[](n.sub);
            }
            [[nodiscard]] constexpr std::vector<T,Allocator>::const_reference operator[](for_debugging::subscript_and_location n) const noexcept(!std::is_same<T,bool>::value){
                n.check_out_of_range(this->size());
                return std::vector<T,Allocator>::operator[](n.sub);
            }
    };
    namespace pmr{
        template<class T> using vector_for_debugging=std::vector_for_debugging<T,std::pmr::polymorphic_allocator<T>>;
    }
}
#define vector vector_for_debugging
#endif
using namespace std;
using ll = long long;
using ull = unsigned long long;
using sll = __int128_t;
using db = double;
using Pr = pair<ll, ll>;
using Pd = pair<double, double>;
using vi = vector<int>;
using vs = vector<string>;
using vc = vector<char>;
using vl = vector<ll>;
using vb = vector<bool>;
using vd = vector<double>;
using vp = vector<Pr>;
using vpd = vector<Pd>;
using vvi = vector<vector<int>>;
using vvc = vector<vector<char>>;
using vvl = vector<vector<ll>>;
using vvp = vector<vector<Pr>>;
using vvb = vector<vector<bool>>;
using vvd = vector<vector<double>>;
using vvs = vector<vector<string>>;
using vvvi = vector<vector<vector<int>>>;
using vvvl = vector<vector<vector<ll>>>;
using vvvb = vector<vector<vector<bool>>>;
using vvvd = vector<vector<vector<double>>>;
using t3 = tuple<ll,ll,ll>;
using t3d = tuple<db,db,db>;
using t4 = tuple<ll,ll,ll,ll>;
using vt3 = vector<t3>;
using vt3d = vector<t3d>;
using vt4 = vector<t4>;
using vvt3 = vector<vector<t3>>;
using vvt3d = vector<vector<t3d>>;
using vvt4 = vector<vector<t4>>;
using pq = priority_queue<Pr,vector<Pr>,greater<Pr>>;
using cl = complex<ll>;
using cd = complex<double>;
#define rep(i, N) for (ll i=0; i<(ll)(N); ++i)
#define repr(i, N) for (ll i = (ll)(N) - 1; i >= 0; --i)
#define repk(i, k, N) for (ll i = k; i < (ll)(N); ++i)
#define rep1(i, N) for (ll i=1; i<(ll)(N+1); ++i)
#define rep1r(i, N) for (ll i=(ll)(N); i>0; i--)
#define all(v) (v).begin(), (v).end()
#define allr(v) (v).rbegin(), (v).rend()
#define SIZE(v) (ll)((v).size())
#define PYes {puts("Yes"); exit(0);}
#define PNo {puts("No"); exit(0);}
#define PFi {puts("First"); exit(0);}
#define PSe {puts("Second"); exit(0);}
#define Pm0 {puts("0"); exit(0);}
#define Pm1 {puts("-1"); exit(0);}
#define INT(...) int __VA_ARGS__; in(__VA_ARGS__)
#define INTM(...) int __VA_ARGS__; inm(__VA_ARGS__)
#define LONG(...) ll __VA_ARGS__; in(__VA_ARGS__)
#define LONGM(...) ll __VA_ARGS__; inm(__VA_ARGS__)
#define DOUBLE(...) double __VA_ARGS__; in(__VA_ARGS__)
#define CHAR(...) char __VA_ARGS__; in(__VA_ARGS__)
#define STRING(...) string __VA_ARGS__; in(__VA_ARGS__)
#define VI(ivec, n) vi ivec(n); input_ivec(ivec, n)
#define VIM(ivec, n) vi ivec(n); input_ivecm(ivec, n)
#define VL(lvec, n) vl lvec(n); input_lvec(lvec, n)
#define VLM(lvec, n) vl lvec(n); input_lvecm(lvec, n)
#define VL2(lvec1, lvec2, n) vl lvec1(n), lvec2(n); input_lvec12(lvec1, lvec2, n)
#define VL2M(lvec1, lvec2, n) vl lvec1(n), lvec2(n); input_lvec12m(lvec1, lvec2, n)
#define VC(cvec, n) vc cvec(n); input_cvec(cvec, n)
#define VS(svec, n) vs svec(n); input_svec(svec, n)
#define VD(dvec, n) vd dvec(n); input_dvec(dvec, n)
#define VP(pvec, n) vp pvec(n); input_pvec(pvec, n)
#define VPD(pvec, n) vpd pvec(n); input_pvecd(pvec, n)
#define VPM(pvec, n) vp pvec(n); input_pvecm(pvec, n)
#define VVI(ivec2, h, w) vvi ivec2(h, vi(w)); input_ivec2(ivec2, h, w)
#define VVL(lvec2, h, w) vvl lvec2(h, vl(w)); input_lvec2(lvec2, h, w)
#define VVLM(lvec2, h, w) vvl lvec2(h, vl(w)); input_lvec2m(lvec2, h, w)
#define VVC(cvec2, h, w) vvc cvec2(h, vc(w)); input_cvec2(cvec2, h, w)
#define pcnt(x) (ll)__builtin_popcountll(x)
#define parity(x) (ll)__builtin_parityll(x)
#define uset unordered_set
#define umap unordered_map
inline void Out(double x) {printf("%.15f",x);cout<<'\n';}
template<typename T> inline void Out(pair<T,T> x) {cout<<x.first<<' '<<x.second<<'\n';}
template<typename T> inline void Out(T x) {cout<<x<<'\n';}
inline void Out(vector<string> v) {rep(i,SIZE(v)) cout<<v[i]<<'\n';}
template<typename T> inline void Out(queue<T> q){while(!q.empty()) {cout<<q.front()<<" "; q.pop();} cout<<endl;}
template<typename T> inline void Out(deque<T> q){while(!q.empty()) {cout<<q.front()<<" "; q.pop_front();} cout<<endl;}
template<typename T> inline void Out(vector<T> v) {rep(i,SIZE(v)) cout<<v[i]<<(i==SIZE(v)-1?'\n':' ');}
template<typename T> inline void Out(vector<vector<T>> &vv){for(auto &v: vv) Out(v);}
template<typename T> inline void Out(vector<pair<T,T>> v) {for(auto p:v) Out(p);}
template<typename T> inline void Outend(T x) {Out(x); exit(0);}
template<typename T> inline void chmin(T &a, T b) { a = min(a, b); }
template<typename T> inline void chmax(T &a, T b) { a = max(a, b); }
inline void mi(void) {return;}
template<typename T1, typename... T2> void mi(T1& f, T2&... r) {--f; mi(r...);}
template<class... T> void in(T&... x) {(cin >> ... >> x);}
template<class... T> void inm(T&... x) {(cin >> ... >> x); mi(x...);}
inline void input_ivec(vi &ivec, int n) {rep(i, n) {cin>>ivec[i];}}
inline void input_ivecm(vi &ivec, int n) {rep(i, n) {cin>>ivec[i];--ivec[i];}}
inline void input_lvec(vl &lvec, ll n) {rep(i, n) {cin>>lvec[i];}}
inline void input_lvecm(vl &lvec, ll n) {rep(i, n) {cin>>lvec[i];--lvec[i];}}
inline void input_lvec12(vl &lvec1, vl &lvec2, ll n) {rep(i, n) {cin>>lvec1[i]>>lvec2[i];}}
inline void input_lvec12m(vl &lvec1, vl &lvec2, ll n) {rep(i, n) {cin>>lvec1[i]>>lvec2[i];--lvec1[i];--lvec2[i];}}
inline void input_cvec(vc &cvec, ll n) {rep (i, n) {cin>>cvec[i];}}
inline void input_svec(vs &svec, ll n) {rep (i, n) {cin>>svec[i];}}
inline void input_dvec(vd &dvec, ll n) {rep (i, n) {cin>>dvec[i];}}
inline void input_pvec(vp &pvec, ll n) {rep (i, n) {cin>>pvec[i].first>>pvec[i].second;}}
inline void input_pvecm(vp &pvec, ll n) {rep (i, n) {cin>>pvec[i].first>>pvec[i].second;pvec[i].first--,pvec[i].second--;}}
inline void input_pvecd(vpd &pvec, ll n) {rep (i, n) {cin>>pvec[i].first>>pvec[i].second;}}
inline void input_ivec2(vvi &ivec2, int h, int w) {rep(i, h) rep(j, w) {cin>>ivec2[i][j];}}
inline void input_lvec2(vvl &lvec2, ll h, ll w) {rep(i, h) rep(j, w) {cin>>lvec2[i][j];}}
inline void input_lvec2m(vvl &lvec2, ll h, ll w) {rep(i, h) rep(j, w) {cin>>lvec2[i][j];--lvec2[i][j];}}
inline void input_cvec2(vvc &cvec2, ll h, ll w) {rep(i, h) rep(j, w) {cin>>cvec2[i][j];}}
inline bool isin(ll i, ll j, ll h, ll w) {if(i<0||i>=h||j<0||j>=w) return false; else return true;}
template<typename T> inline T TmpPercent(T a, T b) {if(b<0){a=-a,b=-b;} return (a%b+b)%b;}
template<typename T> inline T Percent(T a, T b) {if(b<0) return -TmpPercent(a,b); return TmpPercent(a,b);}
template<typename T> inline T Div(T a, T b) {if(b<0){a=-a,b=-b;} return (a-TmpPercent(a,b))/b; }
template<typename T> inline T Divceil(T a, T b) {if(TmpPercent(a,b)==0) return Div(a,b); return Div(a,b)+1;}
template<typename T> void erase(multiset<T> &st, T x) {if(st.contains(x)) st.erase(st.find(x));}
template<typename T> T pop(vector<T> &x) {T ret=x.back(); x.pop_back(); return ret;}
#ifdef __DEBUG
#define de(var) {cerr << #var << ": "; debug_view(var);}
#define de2(var1,var2) {cerr<<#var1<<' '<<#var2<<": "; debug_view(var1,var2);}
#define de3(var1,var2,var3) {cerr<<#var1<<' '<<#var2<<' '<<#var3<<": "; debug_view(var1,var2,var3);}
#define de4(var1,var2,var3,var4) {cerr<<#var1<<' '<<#var2<<' '<<#var3<<' '<<#var4<<": "; debug_view(var1,var2,var3,var4);}
#define de5(var1,var2,var3,var4,var5) {cerr<<#var1<<' '<<#var2<<' '<<#var3<<' '<<#var4<<' '<<#var5<<": "; debug_view(var1,var2,var3,var4,var5);}
template<typename T> inline void debug_view(T e){cerr << e << endl;}
template<typename T1, typename T2> inline void debug_view(T1 e1, T2 e2){cerr<<e1<<' '<<e2<<endl;}
template<typename T1, typename T2, typename T3> inline void debug_view(T1 e1, T2 e2, T3 e3){cerr<<e1<<' '<<e2<<' '<<e3<<endl;}
template<typename T1, typename T2, typename T3, typename T4> inline void debug_view(T1 e1, T2 e2, T3 e3, T4 e4){cerr<<e1<<' '<<e2<<' '<<e3<<' '<<e4<<endl;}
template<typename T1, typename T2, typename T3, typename T4, typename T5> inline void debug_view(T1 e1, T2 e2, T3 e3, T4 e4, T5 e5){cerr<<e1<<' '<<e2<<' '<<e3<<' '<<e4<<' '<<e5<<endl;}
template<typename T1, typename T2> inline void debug_view(pair<T1,T2> &p){cerr<<"{"<<p.first<<" "<<p.second<<"}\n";}
template<typename T1, typename T2> inline void debug_view(vector<pair<T1,T2>> &v){for(auto [a,b]: v){cerr<<"{"<<a<<" "<<b<<"} ";} cerr << endl;}
template<typename T1, typename T2> inline void debug_view(set<pair<T1,T2>> &s){for(auto [a,b]: s){cerr<<"{"<<a<<" "<<b<<"} ";} cerr << endl;}
template<typename T> inline void debug_view(tuple<T,T,T> t){cerr<<get<0>(t)<<' '<<get<1>(t)<<' '<<get<2>(t)<< endl;}
template<typename T> inline void debug_view(queue<T> q){while(!q.empty()) {cerr << q.front() << " "; q.pop();}cerr << endl;}
template<typename T> inline void debug_view(deque<T> q){while(!q.empty()) {cerr << q.front() << " "; q.pop_front();}cerr << endl;}
template<typename T> inline void debug_view(set<T> s){for(auto x:s){cerr << x << ' ';}cerr << endl;}
template<typename T> inline void debug_view(set<T,greater<T>> s){for(auto x:s){cerr << x << ' ';}cerr << endl;}
template<typename T> inline void debug_view(unordered_set<T> s){for(auto x:s){cerr << x << ' ';}cerr << endl;}
template<typename T> inline void debug_view(multiset<T> s){for(auto x:s){cerr << x << ' ';}cerr << endl;}
template<typename T> inline void debug_view(multiset<T,greater<T>> s){for(auto x:s){cerr << x << ' ';}cerr << endl;}
template<typename T> inline void debug_view(vector<pair<T,T>> &v){for(auto [a,b]: v){cerr<<"{"<<a<<" "<<b<<"} ";} cerr << endl;}
inline void debug_view(vector<string> &v){cerr << "----" << endl; for(auto s: v) debug_view(s);}
template<typename T> inline void debug_view(vector<T> &v){for(auto e: v){cerr << e << " ";} cerr << endl;}
template<typename T> inline void debug_view(vector<vector<pair<T,T>>> &vv){cerr << "----" << endl;for(auto &v: vv){debug_view(v);} cerr << "--------" << endl;}
template<typename T> inline void debug_view(vector<vector<T>> &vv){cerr << "----" << endl;for(auto &v: vv){debug_view(v);} cerr << "--------" << endl;}
template<typename T1,typename T2> inline void debug_view(map<T1,T2> &mp){cerr << "----" << endl;for(auto [k,v]: mp){cerr << k << ' ' << v << endl;} cerr << "--------" << endl;}
template<typename T1,typename T2> inline void debug_view(unordered_map<T1,T2> &mp){cerr << "----" << endl;for(auto [k,v]: mp){cerr << k << ' ' << v << endl;} cerr << "--------" << endl;}
template<typename T1,typename T2> inline void debug_view(map<T1,vector<T2>> &mp){cerr<<"----"<<endl;for(auto [k,v]: mp){cerr<<k<<": ";debug_view(v);} cerr << "--------" << endl;}
template<typename T1,typename T2,typename T3> inline void debug_view(map<pair<T1,T2>,T3> &mp){cerr << "----" << endl;for(auto [p,v]: mp){cerr<<'{'<<p.first<<' '<<p.second<<'}'<<": "<<v<<endl;} cerr<<"--------"<<endl;}
#define deb(var) {cerr << #var << ": "; debugb_view(var);}
template<typename T> inline void debugb_view(T e){bitset<20> b(e); cerr<<b<<endl;}
template<typename T> inline void debugb_view(vector<T> &v){cerr<<"----"<<endl;for(auto e: v){debugb_view(e);}}
#else
#define de(var) {}
#define de2(var1,var2) {}
#define de3(var1,var2,var3) {}
#define de4(var1,var2,var3,var4) {}
#define de5(var1,var2,var3,var4,var5) {}
#define deb(var) {}
#endif
int IINF = 1001001001;
ll INF = 3e18;
const ll M998 = 998244353;
const ll M107 = 1000000007;
template<typename T> inline void ch1(T &x){if(x==INF)x=-1;}
const double PI = acos(-1);
const double EPS = 1e-8;  //eg) if x=1e6, EPS >= 1e6/1e14(=1e-8)
const vi di = {0, 1, 0, -1};
const vi dj = {1, 0, -1, 0};
const vp dij = {{0,1},{1,0},{0,-1},{-1,0}};
const vp hex0 = {{-1,-1},{-1,0},{0,-1},{0,1},{1,-1},{1,0}}; // tobide
const vp hex1 = {{-1,0},{-1,1},{0,-1},{0,1},{1,0},{1,1}};  // hekomi
const vi di8 = {-1, -1, -1, 0, 0, 1, 1, 1};
const vi dj8 = {-1, 0, 1, -1, 1, -1, 0, 1};
const vp dij8 = {{0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}};
Pr operator+ (Pr a, Pr b) {return {a.first+b.first, a.second+b.second};}
Pr operator- (Pr a, Pr b) {return {a.first-b.first, a.second-b.second};}
Pr operator* (Pr a, Pr b) {return {a.first*b.first, a.second*b.second};}
Pr operator/ (Pr a, Pr b) {return {a.first/b.first, a.second/b.second};}

struct Bridge {
    using PII = pair<int,int>;
    int n, m, idx;
    vector<vector<PII>> from;
    vector<int> ord, low, bridge, artcl;
    Bridge(int n): n(n), m(0), idx(0), from(n), ord(n,-1), low(n) {}
    void add_edge(int a, int b, int ei=-1) {
        if(ei==-1) {
            from[a].emplace_back(b, m); from[b].emplace_back(a, m);
            ++m;
        } else {
            from[a].emplace_back(b, ei); from[b].emplace_back(a, ei);
        }
    }
    void start_calc() { rep(i, n) if(ord[i]==-1) dfs(i); }
    void dfs(int v, int p=-1) {
        ord[v] = idx++; low[v] = ord[v];
        int c = 0;
        bool art = false;
        for(auto [nv,ei]: from[v]) if(nv!=p) {
            if(ord[nv]!=-1) {
                low[v] = min(low[v], ord[nv]); continue;
            }
            ++c;
            dfs(nv, v);
            low[v] = min(low[v], low[nv]);
            if(low[nv]>ord[v]) bridge.push_back(ei);
            if(low[nv]>=ord[v]) art = true;
        }
        if(p!=-1 && art) artcl.push_back(v);
        if(p==-1 && c>1) artcl.push_back(v);
    }
    vector<int> get_bridge() { return bridge;}
    vector<int> get_articulation() { return artcl;}
};

void solve() {
    LONG(N, M);
    vvp from(N);
    Bridge graph(N);
    vp edge;
    rep(i, M) {
        LONG(a, b);
        from[a].emplace_back(b, i);
        from[b].emplace_back(a, i);
        graph.add_edge(a,b);
        if(a>b) swap(a,b);
        edge.emplace_back(a,b);
    }
    graph.start_calc();
    auto eis = graph.get_bridge();
    vp ans;
    for(auto ei: eis) ans.emplace_back(edge[ei]);

    sort(all(ans));
    for(auto x: ans) Out(x);
    



}

int main () {
    // ios::sync_with_stdio(false);
    cin.tie(nullptr);
    solve();
}

// ### test.cpp ###
accuracy: 1
time_ms: 10
memory_kb: 8948
final_rank: 18

code_snippet: ﻿// ### test.cpp ###
#include <bits/stdc++.h>
#ifdef __DEBUG_VECTOR
namespace for_debugging{
    struct subscript_and_location{
        int sub;
        std::source_location loc;
        subscript_and_location(int sub_,std::source_location loc_=std::source_location::current()){
            sub=sub_;
            loc=loc_;
        }
        void check_out_of_range(size_t sz){
            if(sub<0||(int)sz<=sub){
                std::clog << loc.file_name() << ":(" << loc.line() << ":" << loc.column() << "):" << loc.function_name() << std::endl;
                std::clog << "out of range: subscript = " << sub << ", vector_size = " << sz << std::endl;
                exit(EXIT_FAILURE);
            }
        }
    };
}
namespace std{
    template<class T,class Allocator=std::allocator<T>> class vector_for_debugging:public std::vector<T,Allocator>{
        using std::vector<T,Allocator>::vector;
        public:
            [[nodiscard]] constexpr std::vector<T,Allocator>::reference operator[](for_debugging::subscript_and_location n) noexcept(!std::is_same<T,bool>::value){
                n.check_out_of_range(this->size());
                return std::vector<T,Allocator>::operator[](n.sub);
            }
            [[nodiscard]] constexpr std::vector<T,Allocator>::const_reference operator[](for_debugging::subscript_and_location n) const noexcept(!std::is_same<T,bool>::value){
                n.check_out_of_range(this->size());
                return std::vector<T,Allocator>::operator[](n.sub);
            }
    };
    namespace pmr{
        template<class T> using vector_for_debugging=std::vector_for_debugging<T,std::pmr::polymorphic_allocator<T>>;
    }
}
#define vector vector_for_debugging
#endif
using namespace std;
using ll = long long;
using ull = unsigned long long;
using sll = __int128_t;
using db = double;
using Pr = pair<ll, ll>;
using Pd = pair<double, double>;
using vi = vector<int>;
using vs = vector<string>;
using vc = vector<char>;
using vl = vector<ll>;
using vb = vector<bool>;
using vd = vector<double>;
using vp = vector<Pr>;
using vpd = vector<Pd>;
using vvi = vector<vector<int>>;
using vvc = vector<vector<char>>;
using vvl = vector<vector<ll>>;
using vvp = vector<vector<Pr>>;
using vvb = vector<vector<bool>>;
using vvd = vector<vector<double>>;
using vvs = vector<vector<string>>;
using vvvi = vector<vector<vector<int>>>;
using vvvl = vector<vector<vector<ll>>>;
using vvvb = vector<vector<vector<bool>>>;
using vvvd = vector<vector<vector<double>>>;
using t3 = tuple<ll,ll,ll>;
using t3d = tuple<db,db,db>;
using t4 = tuple<ll,ll,ll,ll>;
using vt3 = vector<t3>;
using vt3d = vector<t3d>;
using vt4 = vector<t4>;
using vvt3 = vector<vector<t3>>;
using vvt3d = vector<vector<t3d>>;
using vvt4 = vector<vector<t4>>;
using pq = priority_queue<Pr,vector<Pr>,greater<Pr>>;
using cl = complex<ll>;
using cd = complex<double>;
#define rep(i, N) for (ll i=0; i<(ll)(N); ++i)
#define repr(i, N) for (ll i = (ll)(N) - 1; i >= 0; --i)
#define repk(i, k, N) for (ll i = k; i < (ll)(N); ++i)
#define rep1(i, N) for (ll i=1; i<(ll)(N+1); ++i)
#define rep1r(i, N) for (ll i=(ll)(N); i>0; i--)
#define all(v) (v).begin(), (v).end()
#define allr(v) (v).rbegin(), (v).rend()
#define SIZE(v) (ll)((v).size())
#define PYes {puts("Yes"); exit(0);}
#define PNo {puts("No"); exit(0);}
#define PFi {puts("First"); exit(0);}
#define PSe {puts("Second"); exit(0);}
#define Pm0 {puts("0"); exit(0);}
#define Pm1 {puts("-1"); exit(0);}
#define INT(...) int __VA_ARGS__; in(__VA_ARGS__)
#define INTM(...) int __VA_ARGS__; inm(__VA_ARGS__)
#define LONG(...) ll __VA_ARGS__; in(__VA_ARGS__)
#define LONGM(...) ll __VA_ARGS__; inm(__VA_ARGS__)
#define DOUBLE(...) double __VA_ARGS__; in(__VA_ARGS__)
#define CHAR(...) char __VA_ARGS__; in(__VA_ARGS__)
#define STRING(...) string __VA_ARGS__; in(__VA_ARGS__)
#define VI(ivec, n) vi ivec(n); input_ivec(ivec, n)
#define VIM(ivec, n) vi ivec(n); input_ivecm(ivec, n)
#define VL(lvec, n) vl lvec(n); input_lvec(lvec, n)
#define VLM(lvec, n) vl lvec(n); input_lvecm(lvec, n)
#define VL2(lvec1, lvec2, n) vl lvec1(n), lvec2(n); input_lvec12(lvec1, lvec2, n)
#define VL2M(lvec1, lvec2, n) vl lvec1(n), lvec2(n); input_lvec12m(lvec1, lvec2, n)
#define VC(cvec, n) vc cvec(n); input_cvec(cvec, n)
#define VS(svec, n) vs svec(n); input_svec(svec, n)
#define VD(dvec, n) vd dvec(n); input_dvec(dvec, n)
#define VP(pvec, n) vp pvec(n); input_pvec(pvec, n)
#define VPD(pvec, n) vpd pvec(n); input_pvecd(pvec, n)
#define VPM(pvec, n) vp pvec(n); input_pvecm(pvec, n)
#define VVI(ivec2, h, w) vvi ivec2(h, vi(w)); input_ivec2(ivec2, h, w)
#define VVL(lvec2, h, w) vvl lvec2(h, vl(w)); input_lvec2(lvec2, h, w)
#define VVLM(lvec2, h, w) vvl lvec2(h, vl(w)); input_lvec2m(lvec2, h, w)
#define VVC(cvec2, h, w) vvc cvec2(h, vc(w)); input_cvec2(cvec2, h, w)
#define pcnt(x) (ll)__builtin_popcountll(x)
#define parity(x) (ll)__builtin_parityll(x)
#define uset unordered_set
#define umap unordered_map
inline void Out(double x) {printf("%.15f",x);cout<<'\n';}
template<typename T> inline void Out(pair<T,T> x) {cout<<x.first<<' '<<x.second<<'\n';}
template<typename T> inline void Out(T x) {cout<<x<<'\n';}
inline void Out(vector<string> v) {rep(i,SIZE(v)) cout<<v[i]<<'\n';}
template<typename T> inline void Out(queue<T> q){while(!q.empty()) {cout<<q.front()<<" "; q.pop();} cout<<endl;}
template<typename T> inline void Out(deque<T> q){while(!q.empty()) {cout<<q.front()<<" "; q.pop_front();} cout<<endl;}
template<typename T> inline void Out(vector<T> v) {rep(i,SIZE(v)) cout<<v[i]<<(i==SIZE(v)-1?'\n':' ');}
template<typename T> inline void Out(vector<vector<T>> &vv){for(auto &v: vv) Out(v);}
template<typename T> inline void Out(vector<pair<T,T>> v) {for(auto p:v) Out(p);}
template<typename T> inline void Outend(T x) {Out(x); exit(0);}
template<typename T> inline void chmin(T &a, T b) { a = min(a, b); }
template<typename T> inline void chmax(T &a, T b) { a = max(a, b); }
inline void mi(void) {return;}
template<typename T1, typename... T2> void mi(T1& f, T2&... r) {--f; mi(r...);}
template<class... T> void in(T&... x) {(cin >> ... >> x);}
template<class... T> void inm(T&... x) {(cin >> ... >> x); mi(x...);}
inline void input_ivec(vi &ivec, int n) {rep(i, n) {cin>>ivec[i];}}
inline void input_ivecm(vi &ivec, int n) {rep(i, n) {cin>>ivec[i];--ivec[i];}}
inline void input_lvec(vl &lvec, ll n) {rep(i, n) {cin>>lvec[i];}}
inline void input_lvecm(vl &lvec, ll n) {rep(i, n) {cin>>lvec[i];--lvec[i];}}
inline void input_lvec12(vl &lvec1, vl &lvec2, ll n) {rep(i, n) {cin>>lvec1[i]>>lvec2[i];}}
inline void input_lvec12m(vl &lvec1, vl &lvec2, ll n) {rep(i, n) {cin>>lvec1[i]>>lvec2[i];--lvec1[i];--lvec2[i];}}
inline void input_cvec(vc &cvec, ll n) {rep (i, n) {cin>>cvec[i];}}
inline void input_svec(vs &svec, ll n) {rep (i, n) {cin>>svec[i];}}
inline void input_dvec(vd &dvec, ll n) {rep (i, n) {cin>>dvec[i];}}
inline void input_pvec(vp &pvec, ll n) {rep (i, n) {cin>>pvec[i].first>>pvec[i].second;}}
inline void input_pvecm(vp &pvec, ll n) {rep (i, n) {cin>>pvec[i].first>>pvec[i].second;pvec[i].first--,pvec[i].second--;}}
inline void input_pvecd(vpd &pvec, ll n) {rep (i, n) {cin>>pvec[i].first>>pvec[i].second;}}
inline void input_ivec2(vvi &ivec2, int h, int w) {rep(i, h) rep(j, w) {cin>>ivec2[i][j];}}
inline void input_lvec2(vvl &lvec2, ll h, ll w) {rep(i, h) rep(j, w) {cin>>lvec2[i][j];}}
inline void input_lvec2m(vvl &lvec2, ll h, ll w) {rep(i, h) rep(j, w) {cin>>lvec2[i][j];--lvec2[i][j];}}
inline void input_cvec2(vvc &cvec2, ll h, ll w) {rep(i, h) rep(j, w) {cin>>cvec2[i][j];}}
inline bool isin(ll i, ll j, ll h, ll w) {if(i<0||i>=h||j<0||j>=w) return false; else return true;}
template<typename T> inline T TmpPercent(T a, T b) {if(b<0){a=-a,b=-b;} return (a%b+b)%b;}
template<typename T> inline T Percent(T a, T b) {if(b<0) return -TmpPercent(a,b); return TmpPercent(a,b);}
template<typename T> inline T Div(T a, T b) {if(b<0){a=-a,b=-b;} return (a-TmpPercent(a,b))/b; }
template<typename T> inline T Divceil(T a, T b) {if(TmpPercent(a,b)==0) return Div(a,b); return Div(a,b)+1;}
template<typename T> void erase(multiset<T> &st, T x) {if(st.contains(x)) st.erase(st.find(x));}
template<typename T> T pop(vector<T> &x) {T ret=x.back(); x.pop_back(); return ret;}
#ifdef __DEBUG
#define de(var) {cerr << #var << ": "; debug_view(var);}
#define de2(var1,var2) {cerr<<#var1<<' '<<#var2<<": "; debug_view(var1,var2);}
#define de3(var1,var2,var3) {cerr<<#var1<<' '<<#var2<<' '<<#var3<<": "; debug_view(var1,var2,var3);}
#define de4(var1,var2,var3,var4) {cerr<<#var1<<' '<<#var2<<' '<<#var3<<' '<<#var4<<": "; debug_view(var1,var2,var3,var4);}
#define de5(var1,var2,var3,var4,var5) {cerr<<#var1<<' '<<#var2<<' '<<#var3<<' '<<#var4<<' '<<#var5<<": "; debug_view(var1,var2,var3,var4,var5);}
template<typename T> inline void debug_view(T e){cerr << e << endl;}
template<typename T1, typename T2> inline void debug_view(T1 e1, T2 e2){cerr<<e1<<' '<<e2<<endl;}
template<typename T1, typename T2, typename T3> inline void debug_view(T1 e1, T2 e2, T3 e3){cerr<<e1<<' '<<e2<<' '<<e3<<endl;}
template<typename T1, typename T2, typename T3, typename T4> inline void debug_view(T1 e1, T2 e2, T3 e3, T4 e4){cerr<<e1<<' '<<e2<<' '<<e3<<' '<<e4<<endl;}
template<typename T1, typename T2, typename T3, typename T4, typename T5> inline void debug_view(T1 e1, T2 e2, T3 e3, T4 e4, T5 e5){cerr<<e1<<' '<<e2<<' '<<e3<<' '<<e4<<' '<<e5<<endl;}
template<typename T1, typename T2> inline void debug_view(pair<T1,T2> &p){cerr<<"{"<<p.first<<" "<<p.second<<"}\n";}
template<typename T1, typename T2> inline void debug_view(vector<pair<T1,T2>> &v){for(auto [a,b]: v){cerr<<"{"<<a<<" "<<b<<"} ";} cerr << endl;}
template<typename T1, typename T2> inline void debug_view(set<pair<T1,T2>> &s){for(auto [a,b]: s){cerr<<"{"<<a<<" "<<b<<"} ";} cerr << endl;}
template<typename T> inline void debug_view(tuple<T,T,T> t){cerr<<get<0>(t)<<' '<<get<1>(t)<<' '<<get<2>(t)<< endl;}
template<typename T> inline void debug_view(queue<T> q){while(!q.empty()) {cerr << q.front() << " "; q.pop();}cerr << endl;}
template<typename T> inline void debug_view(deque<T> q){while(!q.empty()) {cerr << q.front() << " "; q.pop_front();}cerr << endl;}
template<typename T> inline void debug_view(set<T> s){for(auto x:s){cerr << x << ' ';}cerr << endl;}
template<typename T> inline void debug_view(set<T,greater<T>> s){for(auto x:s){cerr << x << ' ';}cerr << endl;}
template<typename T> inline void debug_view(unordered_set<T> s){for(auto x:s){cerr << x << ' ';}cerr << endl;}
template<typename T> inline void debug_view(multiset<T> s){for(auto x:s){cerr << x << ' ';}cerr << endl;}
template<typename T> inline void debug_view(multiset<T,greater<T>> s){for(auto x:s){cerr << x << ' ';}cerr << endl;}
template<typename T> inline void debug_view(vector<pair<T,T>> &v){for(auto [a,b]: v){cerr<<"{"<<a<<" "<<b<<"} ";} cerr << endl;}
inline void debug_view(vector<string> &v){cerr << "----" << endl; for(auto s: v) debug_view(s);}
template<typename T> inline void debug_view(vector<T> &v){for(auto e: v){cerr << e << " ";} cerr << endl;}
template<typename T> inline void debug_view(vector<vector<pair<T,T>>> &vv){cerr << "----" << endl;for(auto &v: vv){debug_view(v);} cerr << "--------" << endl;}
template<typename T> inline void debug_view(vector<vector<T>> &vv){cerr << "----" << endl;for(auto &v: vv){debug_view(v);} cerr << "--------" << endl;}
template<typename T1,typename T2> inline void debug_view(map<T1,T2> &mp){cerr << "----" << endl;for(auto [k,v]: mp){cerr << k << ' ' << v << endl;} cerr << "--------" << endl;}
template<typename T1,typename T2> inline void debug_view(unordered_map<T1,T2> &mp){cerr << "----" << endl;for(auto [k,v]: mp){cerr << k << ' ' << v << endl;} cerr << "--------" << endl;}
template<typename T1,typename T2> inline void debug_view(map<T1,vector<T2>> &mp){cerr<<"----"<<endl;for(auto [k,v]: mp){cerr<<k<<": ";debug_view(v);} cerr << "--------" << endl;}
template<typename T1,typename T2,typename T3> inline void debug_view(map<pair<T1,T2>,T3> &mp){cerr << "----" << endl;for(auto [p,v]: mp){cerr<<'{'<<p.first<<' '<<p.second<<'}'<<": "<<v<<endl;} cerr<<"--------"<<endl;}
#define deb(var) {cerr << #var << ": "; debugb_view(var);}
template<typename T> inline void debugb_view(T e){bitset<20> b(e); cerr<<b<<endl;}
template<typename T> inline void debugb_view(vector<T> &v){cerr<<"----"<<endl;for(auto e: v){debugb_view(e);}}
#else
#define de(var) {}
#define de2(var1,var2) {}
#define de3(var1,var2,var3) {}
#define de4(var1,var2,var3,var4) {}
#define de5(var1,var2,var3,var4,var5) {}
#define deb(var) {}
#endif
int IINF = 1001001001;
ll INF = 3e18;
const ll M998 = 998244353;
const ll M107 = 1000000007;
template<typename T> inline void ch1(T &x){if(x==INF)x=-1;}
const double PI = acos(-1);
const double EPS = 1e-8;  //eg) if x=1e6, EPS >= 1e6/1e14(=1e-8)
const vi di = {0, 1, 0, -1};
const vi dj = {1, 0, -1, 0};
const vp dij = {{0,1},{1,0},{0,-1},{-1,0}};
const vp hex0 = {{-1,-1},{-1,0},{0,-1},{0,1},{1,-1},{1,0}}; // tobide
const vp hex1 = {{-1,0},{-1,1},{0,-1},{0,1},{1,0},{1,1}};  // hekomi
const vi di8 = {-1, -1, -1, 0, 0, 1, 1, 1};
const vi dj8 = {-1, 0, 1, -1, 1, -1, 0, 1};
const vp dij8 = {{0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}};
Pr operator+ (Pr a, Pr b) {return {a.first+b.first, a.second+b.second};}
Pr operator- (Pr a, Pr b) {return {a.first-b.first, a.second-b.second};}
Pr operator* (Pr a, Pr b) {return {a.first*b.first, a.second*b.second};}
Pr operator/ (Pr a, Pr b) {return {a.first/b.first, a.second/b.second};}

struct Bridge {
    using PII = pair<int,int>;
    int n, m, idx;
    vector<vector<PII>> from;
    vector<int> ord, low, bridge, artcl;
    Bridge(int n): n(n), m(0), idx(0), from(n), ord(n,-1), low(n) {}
    void add_edge(int a, int b) {
        from[a].emplace_back(b, m); from[b].emplace_back(a, m);
        ++m;
    }
    void start_calc() { rep(i, n) if(ord[i]==-1) dfs(i); }
    void dfs(int v, int p=-1) {
        ord[v] = idx++; low[v] = ord[v];
        int c = 0;
        bool art = false;
        for(auto [nv,ei]: from[v]) if(nv!=p) {
            if(ord[nv]!=-1) {
                low[v] = min(low[v], ord[nv]); continue;
            }
            ++c;
            dfs(nv, v);
            low[v] = min(low[v], low[nv]);
            if(low[nv]>ord[v]) bridge.push_back(ei);
            if(low[nv]>=ord[v]) art = true;
        }
        if(p!=-1 && art) artcl.push_back(v);
        if(p==-1 && c>1) artcl.push_back(v);
    }
    vector<int> get_bridge() { return bridge;}
    vector<int> get_articulation() { return artcl;}
};

void solve() {
    LONG(N, M);
    vvp from(N);
    Bridge graph(N);
    vp edge;
    rep(i, M) {
        LONG(a, b);
        from[a].emplace_back(b, i);
        from[b].emplace_back(a, i);
        graph.add_edge(a,b);
        if(a>b) swap(a,b);
        edge.emplace_back(a,b);
    }
    graph.start_calc();
    auto eis = graph.get_bridge();
    vp ans;
    for(auto ei: eis) ans.emplace_back(edge[ei]);

    sort(all(ans));
    for(auto x: ans) Out(x);
    



}

int main () {
    // ios::sync_with_stdio(false);
    cin.tie(nullptr);
    solve();
}

// ### test.cpp ###
accuracy: 1
time_ms: 10
memory_kb: 8824
final_rank: 17