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|
s0 t0
s1 t1
:
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.

si and ti 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

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static int[] preNum, parent, lowest;
        static bool[] visited;
        static int timer;

        static void Main(string[] args)
        {
            string[] input = Console.ReadLine().Split(' ');
            int V = int.Parse(input[0]);
            int E = int.Parse(input[1]);

            Dictionary<int, List<int>> G = new Dictionary<int, List<int>>();
            for (int i = 0; i < V; i++) G.Add(i, new List<int>());

            for (int i = 0; i < E; i++)
            {
                input = Console.ReadLine().Split(' ');
                int s = int.Parse(input[0]);
                int t = int.Parse(input[1]);

                G[s].Add(t);
                G[t].Add(s);
            }

            PrintBridges(G, V);
        }

        static void PrintBridges(Dictionary<int, List<int>> G, int V)
        {
            preNum = new int[V];
            parent = new int[V];
            lowest = new int[V];
            visited = new bool[V];
            timer = 1;

            DFS(G, 0, -1);

            List<KeyValuePair<int, int>> ans = new List<KeyValuePair<int, int>>();
            for (int i = 1; i < V; i++)
            {
                int p = parent[i];

                if (preNum[p] < lowest[i])
                {
                    if (p < i) ans.Add(new KeyValuePair<int, int>(p, i));
                    else ans.Add(new KeyValuePair<int, int>(i, p));
                }
            }
            var query = ans.OrderBy(a => a.Key).ThenBy(a => a.Value);

            StringBuilder sb = new StringBuilder();
            foreach (var q in query) sb.AppendLine(q.Key + " " + q.Value);
            Console.Write(sb);
        }

        static void DFS(Dictionary<int, List<int>> G, int cur, int prev)
        {
            preNum[cur] = lowest[cur] = timer;
            timer++;

            visited[cur] = true;

            for (int i = 0; i < G[cur].Count; i++)
            {
                int next = G[cur][i];

                if (!visited[next])
                {
                    parent[next] = cur;

                    DFS(G, next, cur);

                    lowest[cur] = Math.Min(lowest[cur], lowest[next]);
                }
                else if (next != prev)
                {
                    lowest[cur] = Math.Min(lowest[cur], preNum[next]);
                }
            }
        }
    }
}