Problem:
Articulation Points

Find articulation points of a given undirected graph G(V, E).

A vertex in an undirected graph is an articulation point (or cut vertex) iff removing it disconnects the graph.

Input

|V| |E|
s0 t0
s1 t1
:
s|E|-1 t|E|-1

, where |V| is the number of vertices and |E| is the number of edges in the graph. The graph vertices are named with the numbers 0, 1,..., |V|-1 respectively.

si and ti represent source and target verticess of i-th edge (undirected).

Output

A list of articulation points of the graph G ordered by name.

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

Sample Input 2

5 4
0 1
1 2
2 3
3 4

Sample Output 2

1
2
3

Solution in C# (judge verdict: Accepted)

using System;
using System.Linq;
using System.Collections.Generic;
using static System.Console;
using System.Text;
using System.IO;

namespace AOJ
{
    class Program
    {
        static public long[] Sarray() { return ReadLine().Trim().Split().Select(long.Parse).ToArray(); }
        static public List<long> Slist() { return ReadLine().Split().Select(long.Parse).ToList(); }


        //15.3 関節点(Articlulation Point)
        static void Main(string[] args)
        {
            //SetOut(new StreamWriter(OpenStandardOutput()) { AutoFlush = false });
            var VE = Sarray();
            var V = VE[0];
            var E = VE[1];
            var G = new List<long>[V];
            for (var i = 0; i < V; ++i) G[i] = new List<long>();
            for (var i = 0; i < E; ++i)
            {
                var st = Sarray();
                G[st[0]].Add(st[1]);
                G[st[1]].Add(st[0]);
            }
            art_points(G);
        }
        public static void art_points(List<long>[] g)
        {
            var n = g.Length;
            var visited = new bool[n];
            var prenum = new int[n];
            var lowest = new int[n];
            var parent = new int[n];
            Action<int, int> dfs = null;
            int timer = 0;
            dfs = (current, prev) =>
              {
                  prenum[current] = lowest[current] = timer;
                  ++timer;
                  visited[current] = true;
                  foreach (var next in g[current])
                  {
                      if (!visited[next])
                      {
                          parent[next] = current;
                          dfs((int)next, current);
                          lowest[current] = Math.Min(lowest[current], lowest[next]);
                      }
                      else if (next != prev)
                      {
                          lowest[current] = Math.Min(lowest[current], prenum[next]);
                      }
                  }
              };
            dfs(0, -1);
            int np = 0;
            var ans = new HashSet<int>();
            for (int i = 1; i < n; ++i)
            {
                var p = parent[i];
                if (p == 0)
                    ++np;
                else if (prenum[p] <= lowest[i])
                    ans.Add(p);
            }
            if (1 < np) ans.Add(0);
            var ansl = ans.ToList();
            ansl.Sort();
            foreach (var a in ansl)
                WriteLine(a);
        }
    }
}