output_description: A list of _articulation points_ of the graph G ordered by name.
input_description: |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).
attempt: def cut_vertices(E, s):
      N = len(E)
      preorder = [-1] * N  # a dfs preordering of each vertex
      lowpt = [N] * N  # for finding a cut-vertex
      cut_vertex = [False] * N
      root_children = 0  # #(children of the root in the dfs search tree)
      stack = [(s, -1, 0)]  # (vertex, parent, status)
      pre_num = 0  # current preordering
      while stack:
          v, p, st = stack.pop()
          if st == 0 and preorder[v] < 0:  # visited v for the first time
              preorder[v] = pre_num
              lowpt[v] = pre_num
              pre_num += 1
              n_children = 0
              for u in E[v]:
                  if preorder[u] >= 0:
                      if (
                          u != p
                      ):  # the edge (v, u) is a back edge, which is not in dfs search tree
                          lowpt[v] = min(lowpt[v], preorder[u])
                      continue
                  if n_children == 0:
                      stack += [(v, p, 2), (u, v, 0)]
                      n_children += 1
                  else:
                      stack += [(v, p, 1), (u, v, 0)]
                      n_children += 1
              if n_children == 0:  # v is a leaf of the dfs search tree
                  lowpt[p] = min(lowpt[p], lowpt[v])
                  if lowpt[v] >= preorder[p] != 0:
                      cut_vertex[p] = True
                  elif preorder[p] == 0:
                      root_children += 1
          elif st == 0 and preorder[v] >= 0:  # the edge (v, p) is a back edge
              continue
          elif st == 1:  # now searching
              continue
          else:  # search finished
              if p != -1:
                  lowpt[p] = min(lowpt[p], lowpt[v])
                  if lowpt[v] >= preorder[p] != 0:
                      cut_vertex[p] = True
                  elif preorder[p] == 0:
                      root_children += 1
              else:
                  if root_children >= 2:
                      cut_vertex[v] = True
      return cut_vertex
  
  
  N, M = map(int, input().split())
  E = [[] for _ in range(N)]
  for _ in range(M):
      s, t = map(int, input().split())
      E[s].append(t)
      E[t].append(s)
  temp = cut_vertices(E, 0)
  cut_vs = [v for v in range(N) if temp[v]]
  if cut_vs:
      print(*cut_vs, sep="\n")
  
problem_description: 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.
samples: [{"input": "4 4\n    0 1\n    0 2\n    1 2\n    2 3", "output": "2"}, {"input": "5 4\n    0 1\n    1 2\n    2 3\n    3 4", "output": "1\n    2\n    3"}]