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.Collections.Generic;
using System.Linq;

namespace CSharpSample01
{

    class Program
    {

        static bool[] visit;
        static List<int>[] g;
        static int timer;
        static int[] prenum;
        static int[] parent;
        static int[] lowest;
        static int N;

        static void Dfs(int current, int prev)
        {
            visit[current] = true;
            prenum[current] = lowest[current] = timer;
            timer++;

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

                if (!visit[next])
                {
                    parent[next] = current;

                    Dfs(next, current);

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


            }

        }

        static void Solve()
        {

            for(int i = 0; i < N; i++)
            {
                visit[i] = false;            
            }

            //lowestを求める
            Dfs(0, -1);

            var ans = new SortedSet<int>();

            int son_root = 0;

            //lowestをもとに関節点かどうかを判断
            for(int i = 1; i < N; i++)
            {
                int p = parent[i];
                if(p == 0)
                {
                    son_root++;
                }
                else if (prenum[p] <= lowest[i])
                {
                    ans.Add(p);
                }

            }

            if(son_root >= 2)
            {
                ans.Add(0);
            }

            

            foreach(var s in ans)
            {
                Console.WriteLine(s);
            }

        }

        
        static void Main(string[] args)
        {
            string[] str = Console.ReadLine().Split(' ');

            N = int.Parse(str[0]);
            int m = int.Parse(str[1]);

            visit = new bool[N];
            g = new List<int>[N];
            timer = 1;
            prenum = new int[N];
            parent = new int[N];
            lowest = new int[N];

            for(int i = 0; i < N; i++)
            {
                g[i] = new List<int>();
            }


            for(int i = 0; i < m; i++)
            {
                string[] input = Console.ReadLine().Split(' ');

                int u = int.Parse(input[0]);
                int v = int.Parse(input[1]);

                g[u].Add(v);
                g[v].Add(u);
            }

            Solve();

        }
    }
}