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.Collections;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using static System.Math;
using System.Numerics;
static class Program{
    const int mod=(int)1e9+7;
    static List<int>[] li;
    static bool[] b;
    static int[] h;
    static int[] ord,low;
    static int g=0;
    static List<int> ans;
    static void Main(){
        Sc sc=new Sc();
        int[] s=sc.Ia;
        int n=s[0],m=s[1];
        if(m==0){return;}
        li=new List<int>[n+1];
        b=new bool[n+1];
        h=new int[n+1];
        ord=new int[n];
        low=new int[n];
        ans=new List<int>();
        for(int i=0;i<n;i++){li[i]=new List<int>();}
        for(int i=0;i<m;i++){
            int[] e=sc.Ia;
            li[e[0]].Add(e[1]);
            li[e[1]].Add(e[0]);
        }
        Fu(0);
        var ans2=ans.OrderBy(x=>x).ToArray();
        StringBuilder sb=new StringBuilder();
        foreach(var e in ans2){sb.Append(e+"\n");}
        Console.Write(sb);
    }
    static void Fu(int a){
        h[a]=1;
        ord[a]=g;
        low[a]=g;
        g++;
        for(int i=0;i<li[a].Count;i++){
            if(h[li[a][i]]==0){
                Fu(li[a][i]);
                low[a]=Min(low[li[a][i]],low[a]);
                if(a==0){h[a]++;if(h[a]==3){ans.Add(a);}}
                else if(h[a]==1&&ord[a]<=low[li[a][i]]){ans.Add(a);h[a]|=2;}
            }
            else{low[a]=Min(ord[li[a][i]],low[a]);}
        }
    }
}
 
public class Sc{
    public int I{get{return int.Parse(Console.ReadLine());}}
    public long L{get{return long.Parse(Console.ReadLine());}}
    public double D{get{return double.Parse(Console.ReadLine());}}
    public string S{get{return Console.ReadLine();}}
    public int[] Ia{get{return Array.ConvertAll(Console.ReadLine().Split(),int.Parse);}}
    public long[] La{get{return Array.ConvertAll(Console.ReadLine().Split(),long.Parse);}}
    public double[] Da{get{return Array.ConvertAll(Console.ReadLine().Split(),double.Parse);}}
    public string[] Sa{get{return Console.ReadLine().Split();}}
    public object[] Oa{get{return Console.ReadLine().Split();}}
    public int[] Ia2{get{return Array.ConvertAll(("0 "+Console.ReadLine()+" 0").Split(),int.Parse);}}
    public int[] Ia3(int a){return Array.ConvertAll((a.ToString()+" "+Console.ReadLine()).Split(),int.Parse);}
    public int[] Ia3(bool a,int b,bool c,int d){return Array.ConvertAll(((a?b.ToString()+" ":"")+Console.ReadLine()+(c?" "+d.ToString():"")).Split(),int.Parse);}
    public long[] La2{get{return Array.ConvertAll(("0 "+Console.ReadLine()+" 0").Split(),long.Parse);}}
    public long[] La3(int a){return Array.ConvertAll((a.ToString()+" "+Console.ReadLine()).Split(),long.Parse);}
    public long[] La3(bool a,int b,bool c,int d){return Array.ConvertAll(((a?b.ToString()+" ":"")+Console.ReadLine()+(c?" "+d.ToString():"")).Split(),long.Parse);}
    public T[] Arr<T>(int n,Func<T> f){var a=new T[n];for(int i=0;i<n;i++){a[i]=f();}return a;}
    public T[] Arr<T>(int n,Func<int,T> f){var a=new T[n];for(int i=0;i<n;i++){a[i]=f(i);}return a;}
    public T[] Arr<T>(int n,Func<string[],T> f){var a=new T[n];for(int i=0;i<n;i++){a[i]=f(Console.ReadLine().Split());}return a;}
    public T[] Arr<T>(int n,Func<int,string[],T> f){var a=new T[n];for(int i=0;i<n;i++){a[i]=f(i,Console.ReadLine().Split());}return a;}
}