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|  s 0  t 0  s 1  t 1 : 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.  s i and t i 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 (Python):
import sys

def input(): return sys.stdin.readline().strip()
def list2d(a, b, c): return [[c] * b for i in range(a)]
def list3d(a, b, c, d): return [[[d] * c for j in range(b)] for i in range(a)]
def list4d(a, b, c, d, e): return [[[[e] * d for j in range(c)] for j in range(b)] for i in range(a)]
def ceil(x, y=1): return int(-(-x // y))
def INT(): return int(input())
def MAP(): return map(int, input().split())
def LIST(N=None): return list(MAP()) if N is None else [INT() for i in range(N)]
def Yes(): print('Yes')
def No(): print('No')
def YES(): print('YES')
def NO(): print('NO')
sys.setrecursionlimit(10 ** 9)
INF = 10 ** 18
MOD = 10 ** 9 + 7

def low_link(nodes):
    N = len(nodes)
    visited = [False] * N
    prenum = [0] * N
    parent = [0] * N
    lowest = [0] * N
    bridges = []
    timer = 1

    def rec(cur, prev, timer):
        
        prenum[cur] = lowest[cur] = timer
        timer += 1
        visited[cur] = True
        for nxt in nodes[cur]:
            if not visited[nxt]:
                
                parent[nxt] = cur
                timer = rec(nxt, cur, timer)
                
                lowest[cur] = min(lowest[cur], lowest[nxt])
                
                if lowest[nxt] == prenum[nxt]:
                    
                    bridges.append((min(cur, nxt), max(cur, nxt)))
            elif nxt != prev:
                
                lowest[cur] = min(lowest[cur], prenum[nxt])
        return timer
    
    for i in range(N):
        if not visited[i]:
            timer = rec(i, -1, timer)

    
    aps = set()
    
    np = 0
    for i in range(1, N):
        p = parent[i]
        if p == 0:
            np += 1
        
        elif prenum[p] <= lowest[i]:
            aps.add(p)
    
    if np > 1:
        aps.add(0)

    return aps, bridges

N, M = MAP()
nodes = [[] for i in range(N)]
for i in range(M):
    u, v = MAP()
    nodes[u].append(v)
    nodes[v].append(u)

aps, bridges = low_link(nodes)

aps = sorted(aps)
for x in aps:
    print(x)

Solution (Python):

import sys
class LowLinks:
    def __init__(self, edges, v, root=0):
        self.edges = edges
        self.root = root
        self.ord = [None] * v
        self.low = [None] * v
        self.cnt = 0
        self.bridges = []
        self.articulations = set()
        self.par = [None] * v

    def build(self):
        self.search(self.root)

    def search(self, x):
        self.ord[x] = self.cnt
        self.low[x] = self.cnt
        self.cnt += 1
        dim = 0
        for to in self.edges[x]:
            if to == self.par[x]:continue
            if self.ord[to] != None:
                self.low[x] = min(self.low[x], self.ord[to])
            else:
                self.par[to] = x
                self.search(to)
                dim += 1
                self.low[x] = min(self.low[x], self.low[to])

                if x != self.root and self.ord[x] <= self.low[to]:
                    self.articulations.add(x)

            if x == self.root and dim > 1:
                self.articulations.add(x)

            if self.ord[x] < self.low[to]:
                self.bridges.append((x, to))

sys.setrecursionlimit(1000000)
n,m=map(int,input().split())
edges=[[] for _ in range(n)]
for _ in range(m):
    s, t = map(int, input().split())
    edges[s].append(t)
    edges[t].append(s)

l=LowLinks(edges,n)
l.build()
for i in sorted(l.articulations):
    print(i)

Solution (Python):
from typing import List
from typing import Tuple
from sys import setrecursionlimit

setrecursionlimit(100000)

def articulation_points(adj, n):
    low_link = [None for _ in range(n)]
    mark = [False for _ in range(n)]
    id = [-1 for _ in range(n + 1)]
    points = []

    for v in range(n):
        if mark[v]:
            continue
        dfs(v, -1, adj, id, low_link, mark, points)
    points.sort()
    return points

def dfs(v: int, p: int, adj: List[List[int]], id: List[int], low_link: List[int], mark: List[bool], points: List[int]) -> None:
    mark[v] = True
    id[-1] += 1
    id[v] = id[-1]
    low_link[v] = id[v]

    is_articulation_point = False
    childs = 1 if p != -1 else 0 

    for a_v in adj[v]:
        if a_v == p: continue
        if not mark[a_v]:
            childs += 1
            dfs(a_v, v, adj, id, low_link, mark, points)
            low_link[v] = min(low_link[v], low_link[a_v])
            if childs > 1 and id[v] <= low_link[a_v]:
                is_articulation_point = True
        else:
            low_link[v] = min(low_link[v], id[a_v])
    if is_articulation_point:
        points.append(v)

def read() -> Tuple[List[List[int]], int]:
    v, e = tuple([int(i) for i in input().split()])

    adj = [[] for _ in range(v)]

    for i in range(e):
        v1, v2 = tuple([int(j) for j in input().split()])
        adj[v1].append(v2)
        adj[v2].append(v1)
    
    return adj, v

def write(point_list):
    for point in point_list:
        print(point)

adj, n = read()
articulation_point_list = articulation_points(adj, n)
write(articulation_point_list)

Solution (Python):

from collections import defaultdict, deque
from heapq import heappush, heappop
from itertools import permutations, accumulate
import sys
import math
import bisect
def LI(): return [int(x) for x in sys.stdin.readline().split()]
def I(): return int(sys.stdin.readline())
def LS():return [list(x) for x in sys.stdin.readline().split()]
def S():
    res = list(sys.stdin.readline())
    if res[-1] == "\n":
        return res[:-1]
    return res
def IR(n):
    return [I() for i in range(n)]
def LIR(n):
    return [LI() for i in range(n)]
def SR(n):
    return [S() for i in range(n)]
def LSR(n):
    return [LS() for i in range(n)]

sys.setrecursionlimit(1000000)
mod = 1000000007

class LowLink:
    def __init__(self, v):
        self.size = len(v)
        self.v = v
        self.pre = [None]*self.size
        self.low = [None]*self.size
        self.articulation = []
        self.bridge = []
        for x in range(self.size):
            if self.pre[x] is None:
                self.cnt = 0
                self.dfs(x,None)

    def dfs(self, x, par):
        self.pre[x] = self.low[x] = self.cnt
        self.cnt += 1
        is_articulation = False
        n = 0
        for y in self.v[x]:
            if self.pre[y] is None:
                n += 1
                lowy = self.dfs(y, x)
                if lowy < self.low[x]:
                    self.low[x] = lowy
                if self.pre[x] <= lowy:
                    if self.pre[x]:
                        is_articulation = True
                    if self.pre[x] < lowy:
                        self.bridge.append((x,y))
            else:
                if par != y and self.pre[y] < self.low[x]:
                    self.low[x] = self.pre[y]

        if par is None and n > 1:
            is_articulation = True

        if is_articulation:
            self.articulation.append(x)

        return self.low[x]


def solve():
    n,m = LI()
    v = [[] for i in range(n)]
    for i in range(m):
        a,b = LI()
        v[a].append(b)
        v[b].append(a)
    lowlink = LowLink(v)
    for i in sorted(lowlink.articulation):
        print(i)
    return


if __name__ == "__main__":
    solve()

Solution (Python):
import sys
sys.setrecursionlimit(10**7)

def run():
  V, E = map(int, input().split())
  if V == 1: exit()
  g = {}
  for e in range(E):
    A, B = map(int, input().split())
    g.setdefault(B, []).append(A)
    g.setdefault(A, []).append(B)
  order = [0]*V
  count = 0
  art = []
  def dfs(now, prev):
    nonlocal count
    fcount = artflag = 0
    count += 1
    low_p = order[now-1] = count
    for nxt in g[now]:
      if nxt == prev:
        continue
      if order[nxt-1] == 0:
        nxt_low_p = dfs(nxt, now)
        artflag |= nxt_low_p >= order[now-1]
        low_p = min(low_p, nxt_low_p)
        fcount += 1
      else:
        low_p = min(low_p, order[nxt-1])
    if (prev == -1 and fcount > 1) or (prev != -1 and artflag):
      art.append(now)
    return low_p
  dfs(1, -1)
  for a in sorted(art):
    print(a)
  
if __name__ == '__main__':
  run()

Solution (Python):
import sys
sys.setrecursionlimit(10**7)


def DFS(s,p):
    global timer
    prenum[s]=lowest[s]=timer
    timer +=1
    parent[s]=p
    color[s]="gray"

    for i in G[s]:
        if color[i]=="white":
            DFS(i,s)
            lowest[s]=min(lowest[s],lowest[i])
        else:
            lowest[s]=min(lowest[s],prenum[i])
    color[s]="black"


def art_point():
    A=set()
    root=0
    for i,j in enumerate(parent):
        if j==-1:continue
        elif prenum[j]<=lowest[i]:
            A.add(j)
        if j==0:root +=1
    if root==1:A.remove(0)

    return set(A)


v,e=map(int,input().split())
G=[[] for _ in range(v)]

for i in range(e):
    s,t=map(int,input().split())
    G[s].append(t)
    G[t].append(s)

prenum=[0 for _ in range(v)]
parent=[0 for _ in range(v)]
lowest=[float("inf") for _ in range(v)]
timer=1
color=["white" for _ in range(v)]

DFS(0,-1)
A=art_point()

for i in sorted(A):
    print(i)

Solution (Python):























































































timer = 0


def find_articulation(node, visited, disc, low, parent, ap, tonodes):
    global timer
    children = 0
    visited[node] = True
    disc[node] = low[node] = timer
    timer += 1
    for nextnode in tonodes[node]:
        if not visited[nextnode]:
            parent[nextnode] = node
            children += 1
            find_articulation(nextnode, visited, disc, low, parent, ap, tonodes)
            low[node] = min(low[node], low[nextnode])
            if parent[node] is None and children > 1:
                
                ap[node] = True
            if parent[node] is not None and low[nextnode] >= disc[node]:
                
                ap[node] = True
        elif nextnode != parent[node]:
            low[node] = min(low[node], disc[nextnode])


def articulation(tonodes, v):
    visited = [False for _ in range(v)]
    disc = [float("inf") for _ in range(v)]  
    low = [float("inf") for _ in range(v)]  
    parent = [None for _ in range(v)]  
    ap = [False for _ in range(v)]  
    global timer
    timer = 0
    for i in range(v):
        if not visited[i]:
            find_articulation(i, visited, disc, low, parent, ap, tonodes)
    for i in range(v):
        if ap[i]:
            print(i)


def main():
    ve = input().split()
    v, e = tuple(map(int, ve))
    tonodes = [[] for _ in range(v)]
    for _ in range(e):
        st = input().split()
        s, t = tuple(map(int, st))
        tonodes[s].append(t)
        tonodes[t].append(s)
    articulation(tonodes, v)


if __name__ == "__main__":
    import sys
    sys.setrecursionlimit(999999)
    main()

Solution (Python):
def cut_vertices(E, s):
    N = len(E)
    preorder = [-1] * N 
    lowpt = [N] * N 
    cut_vertex = [False] * N
    root_children = 0 
    stack = [(s, -1, 0)] 
    pre_num = 0 
    while stack:
        v, p, st = stack.pop()
        if st == 0 and preorder[v] < 0: 
            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: 
                        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: 
                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: 
            continue
        elif st == 1: 
            continue
        else: 
            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')

Solution (Python):


import sys

sys.setrecursionlimit(100000)


v, e = map(int, sys.stdin.readline().strip().split())
G = [[] for _ in range(v)]
indeg = [0] * v
for i in range(e):
    s, t = map(int, sys.stdin.readline().strip().split())
    G[s].append(t)
    G[t].append(s)
    indeg[t] += 1


visit = [False] * v
lowest = [v+1] * v
prenum = [-1] * v
parent = [-1] * v
time = 0


def dfs(current, prev):
    global time
    prenum[current] = time
    lowest[current] = time
    visit[current] = True
    time += 1

    for i in G[current]:
        next = i
        if not visit[next]:
            parent[next] = current

            dfs(next, current)
            lowest[current] = min(lowest[current], lowest[next])
        elif next != prev:
            lowest[current] = min(lowest[current], prenum[next])


def art_points():
    dfs(0, -1)

    np = 0  
    articulationPoint = [] 
    for i in range(1, v):
        if parent[i] == 0:
            np += 1
        elif lowest[i] >= prenum[parent[i]]:
            if parent[i] not in articulationPoint:
                articulationPoint.append(parent[i])

    if np > 1:
        articulationPoint.append(0)

    
    articulationPoint.sort()

    return articulationPoint


def main():
    ans = art_points()
    for i in ans:
        print(i)


if __name__ == '__main__':
    main()

Solution (Python):


import heapq
import sys
NIL = -1

def dfs(current, prev):
    global timer
    lowest[current] = timer
    prenum[current] = timer
    timer += 1
    visited[current] = True
    
    for i in range(len(G[current])):
        nex = G[current][i]
        if visited[nex] == False:
            parent[nex] = current
            
            dfs(nex, current)

            
            lowest[current] = min(lowest[current], lowest[nex])
        elif(nex != prev):
            lowest[current] = min(lowest[current], prenum[nex])


sys.setrecursionlimit(1000000)

nums=list(map(int,input().split()))
n = nums[0]
e = nums[1]

G = [[] for j in range(n)]
for i in range(e):
    nums=list(map(int,input().split()))
    G[nums[0]].append(nums[1])
    G[nums[1]].append(nums[0])

S = []
visited = [False] * n
parent = [NIL] * n
prenum = [NIL] * n
lowest = [NIL] * n
timer = 1

dfs(0, -1)

ap = set()
np = 0

for i in range(n):
    p = parent[i]
    if p == 0:
        np += 1
    elif prenum[p] <= lowest[i]:
        ap.add(p)
if np > 1:
    ap.add(0)
ap = list(ap)

heapq.heapify(ap)
for i in range(len(ap)):
    x = heapq.heappop(ap)
    if x != NIL:
        print(x)

Solution (Python):
import sys
sys.setrecursionlimit(30000)

v,e=map(int,input().split())

class node:
    def __init__(self, i):
        self.edge=[]
        self.low=0
        self.num=0
        self.visited=False
        self.child=[]
        self.id=i
        
nodes=[node(i) for i in range(v)]
for _ in range(e):
    s,t=map(int,input().split())
    nodes[s].edge.append(t)
    nodes[t].edge.append(s)
    
num=0
def dfs(node):
    global num
    node.num=num
    num+=1
    node.visited=True
    node.low=node.num
    for e in node.edge:
        if not nodes[e].visited:
            dfs(nodes[e])
            node.low=min(node.low, nodes[e].low)
            node.child.append(e)
        else:
            node.low=min(node.low, nodes[e].num)
            
dfs(nodes[0])
            
if len(nodes[0].child)>=2: print(0)
for node in nodes[1:]:
    for e in node.child:
        if node.num <= nodes[e].low:
            print(node.id)
            break

Solution (Python):
import sys
input = sys.stdin.readline
from operator import itemgetter
sys.setrecursionlimit(10000000)
INF = 10**30


def make_adj_list():
    n, E = map(int, input().strip().split()) 
    l = [[] for _ in range(n)] 
    for i in range(E):
        s, t = map(int, input().strip().split())
        l[s].append(t)
        l[t].append(s)

    return l, n, E

G = []
prenum = []
parent = []
lowest = []
order = 1
visited = []

def dfs(v, fr):
    global G, prenum, parent, lowest, order, visited
    visited[v] = True
    prenum[v] = lowest[v] = order
    order += 1
    
    for node in G[v]:
        if not visited[node]:
            parent[node] = v
            dfs(node, v)
            lowest[v] = min(lowest[v], lowest[node]) 
        elif node != fr:
            lowest[v] = min(lowest[v], prenum[node]) 


def main():
    global G, prenum, parent, lowest, visited
    ans = set()
    G, n, e = make_adj_list()
    prenum = [INF] * n
    parent = [INF] * n
    lowest = [INF] * n
    visited = [False] * n
    dfs(0, -1)

    c = 0
    for i in range(1, n):
        p = parent[i]
        if p == 0:
            c += 1
        elif prenum[p] <= lowest[i]:
            ans.add(p)
    if c >= 2:
        ans.add(0)
    ans = sorted(list(ans))
    for i in ans:
        print(i)


if __name__ == '__main__':
    main()

Solution (Python):








INF = 10**6 + 1
import sys
sys.setrecursionlimit(2**16 - 1)
from collections import defaultdict
G = defaultdict(lambda: [])

n_V, n_E = list(map(int, input().split()))

for _ in range(n_E):
    s, t = list(map(int, input().split()))
    G[s].append(t)
    G[t].append(s)


def get_art_point(G, n_V):
    
    
    prenum = [None] * n_V
    parent = [None] * n_V
    lowest = [INF] * n_V
    timer = 0  
    is_visited = [False] * n_V  
    root = 0

    
    def dfs(cur, prev):  
        
        nonlocal timer  
        prenum[cur] = lowest[cur] = timer  
        timer += 1
        parent[cur] = prev
        is_visited[cur] = True

        
        for nx in G[cur]:  
            if (not is_visited[nx]):
                dfs(nx, cur)
                lowest[cur] = min(lowest[cur], lowest[nx]
                                  )  
            elif nx != prev:  
                
                lowest[cur] = min(lowest[cur], prenum[nx])

    
    def art_points(root):
        
        ret = set()
        n_p_is_root = root  
        
        for u, p in enumerate(parent):
            if p is None:
                
                continue
            elif p == root:
                
                n_p_is_root += 1

            if prenum[p] <= lowest[u]:
                ret.add(p)
        if n_p_is_root == 1:
            
            ret.remove(0)
        return ret

    
    dfs(root, None)
    return art_points(root)


ans = list(get_art_point(G, n_V))
ans.sort()
if ans:
    print(*ans, sep='\n')
else:
    pass

Solution (Python):
def solve():
    N, M = map(int, input().split())
    edges = [[] for _ in [0] * N]
    for _ in [0] * M:
        a, b = map(int, input().split())
        edges[a].append(b)
        edges[b].append(a)
    for v in sorted(get_lowlink(edges, M)[1]):
        print(v)


def get_lowlink(edges, edge_num):
    import sys
    sys.setrecursionlimit(10**7)

    n = len(edges)
    order = [-1] * n
    low = [float("inf")] * n
    bridges = []
    articulations = [0] if edge_num == n-1 and len(edges[0]) > 1 else []
    append_bridge, append_articulation = bridges.append, articulations.append

    def dfs(v, prev, k):
        order[v] = low[v] = k

        is_articulation = False
        for dest in edges[v]:
            if order[dest] == -1:
                dfs(dest, v, k + 1)
                if low[v] > low[dest]:
                    low[v] = low[dest]
                if order[v] < low[dest]:
                    append_bridge((v, dest))
                is_articulation |= order[v] <= low[dest]

            elif dest != prev and low[v] > order[dest]:
                low[v] = order[dest]

        if v > 0 and is_articulation:
            append_articulation(v)

    dfs(0, 0, 0)
    return bridges, articulations


if __name__ == "__main__":
    solve()

Solution (Python):
from typing import List, Set
import sys
sys.setrecursionlimit(1000000) 

def dfs(current: int, prev: int) -> None:
	global timer
	
	prenum[current] = timer
	lowest[current] = timer
	timer += 1
	visited[current] = True
	for next_v in G[current]:
		if not visited[next_v]:
			
			parent[next_v] = current
			dfs(next_v, current)
			
			lowest[current] = min(lowest[current], lowest[next_v])
		elif next_v != prev:
			
			lowest[current] = min(lowest[current], prenum[next_v])

def art_points() -> Set[int]:
	
	dfs(0, -1) 
	np: int = 0
	ap: Set[int] = set()
	for i in range(1, n):
		p = parent[i]
		if p == 0:
			np += 1
		elif prenum[p] <= lowest[i]:
			ap.add(p)
	if np > 1:
		ap.add(0)
	return ap


if __name__ == "__main__":
	n, m = map(int, input().split())
	G: List[List[int]] = [[] for _ in range(n)]
	prenum: List[int] = [0 for _ in range(n)]
	parent: List[int] = [-1 for _ in range(n)]
	lowest: List[int] = [0 for _ in range(n)]
	visited: List[bool] = [False for _ in range(n)]
	timer = 1
	for _ in range(m):
		s, t = map(int, input().split())
		G[s].append(t)
		G[t].append(s)
	ap = art_points()
	ap = sorted(ap)
	for p in ap:
		print(p)

Solution (Python):
from sys import setrecursionlimit

setrecursionlimit(1000000)


def art_points(n, m, G):
    def dfs(cur, prev):
        nonlocal t
        prenum[cur] = lowest[cur] = t
        t += 1
        visited[cur] = True

        for ne in G[cur]:
            if not visited[ne]:
                parent[ne] = cur
                dfs(ne, cur)
                lowest[cur] = min(lowest[cur], lowest[ne])
            elif ne != prev:
                lowest[cur] = min(lowest[cur], prenum[ne])

    t = 1
    prenum = [0] * n
    parent = [0] * n
    lowest = [0] * n
    visited = [False] * n
    dfs(0, -1)

    ap = set()
    np = 0
    for i, p in zip(range(1, n), parent[1:]):
        if p == 0:
            np += 1
        elif prenum[p] <= lowest[i]:
            ap.add(p)
    if np > 1:
        ap.add(0)
    return ap


def main():
    n, m = [int(x) for x in input().split()]
    G = [[] for _ in range(n)]
    for _ in range(m):
        s, t = [int(x) for x in input().split()]
        G[s].append(t)
        G[t].append(s)
    for p in sorted(art_points(n, m, G)):
        print(p)


main()

Solution (Python):



import sys

sys.setrecursionlimit(100000)

V, E = list(map(int, input().split()))
Edge = [list(map(int, input().split())) for _ in range(0, E)]

ord = [0 for _ in range(0, V)]
low = [0 for _ in range(0, V)]
used = [False for _ in range(0, V)]
articulation = []

G = [ [] for _ in range(0, V)]
for s, t in Edge:
    G[s] += [t]
    G[t] += [s]

def dfs(s, p, k):
    global articulation
    used[s] = True
    ord[s] = k
    low[s] = ord[s]
    k += 1
    c = 0
    for t in G[s]:
        if used[t] == False:
            c += 1
            dfs(t, s, k)
            low[s] = min(low[s], low[t])
            if p != -1 and ord[s] <= low[t]:
                articulation += [s]
        elif t != p:
            low[s] = min(low[s], ord[t])
    if p == -1 and c >= 2:
        articulation += [s]
 
for s in range(0, V): 
    if used[s] == False:
        dfs(s, -1, 0)

answer = list(set(articulation))
answer.sort()
if len(articulation) > 0:
    print("\n".join(list(map(str, answer))))

Solution (Python):
import sys
from typing import List, Set


sys.setrecursionlimit(200000)


def dfs(cur : int, prev: int) -> None:
    global prenum, parent, lowest, counter
    prenum[cur] = lowest[cur] = counter
    counter += 1
    for edge in edges[cur]:
        if prenum[edge] != sys.maxsize:
            if edge != prev:
                lowest[cur] = min(lowest[cur], prenum[edge])
            continue
        parent[edge] = cur
        dfs(edge, cur)
        lowest[cur] = min(lowest[cur], lowest[edge])


if __name__ == "__main__":
    V, E = map(int, input().split())
    edges: List[Set[int]] = [set() for _ in range(V)]

    for _ in range(E):
        s, t = map(int, input().split())
        edges[s].add(t)
        edges[t].add(s)

    prenum = [sys.maxsize] * V
    parent = [sys.maxsize] * V
    lowest = [sys.maxsize] * V
    counter = 0

    dfs(0, 1)
    ap: List[bool] = [False] * V
    r = 0
    for _ in filter(lambda x: x == 0, parent):  
        r += 1
        if r > 1:
            ap[0] = True
            break

    for i in range(1, V):
        p = parent[i]
        if p and prenum[p] <= lowest[i]:
            ap[p] = True

    for i, e in enumerate(ap):
        if e:
            print(i)

Solution (Python):
import sys
sys.setrecursionlimit(10**6)
readline = sys.stdin.readline
write = sys.stdout.write

N, M = map(int, readline().split())

G = [[] for i in range(N)]
for i in range(M):
    u, v = map(int, readline().split())
    G[u].append(v)
    G[v].append(u)


def construct(G, N):
    P = [0]*N
    G0 = [[] for i in range(N)]
    V = []
    lb = [0]*N
    def dfs(v, p):
        P[v] = p
        V.append(v)
        lb[v] = len(V)
        for w in G[v]:
            if w == p:
                continue
            if lb[w]:
                if lb[v] < lb[w]:
                    
                    G0[v].append(w)
                continue
            
            dfs(w, v)
    dfs(0, -1)

    used = [0]*N
    first = 1
    B = []
    used[0] = 1
    ap = [0]*N
    for u in V:
        if not used[u]:
            
            p = P[u]
            B.append((u, p) if u < p else (p, u))
            if len(G[u]) > 1:
                ap[u] = 1
            if len(G[p]) > 1:
                ap[p] = 1
        cycle = 0
        for v in G0[u]:
            w = v
            while w != u and not used[w]:
                used[w] = 1
                w = P[w]
            if w == u:
                cycle = 1
        if cycle:
            if not first:
                ap[u] = 1
            first = 0
    
    A = [v for v in range(N) if ap[v]]

    return B, A

B, A = construct(G, N)

for v in A:
    write("%d\n" % v)

Solution (Python):
import sys
readline = sys.stdin.readline


sys.setrecursionlimit(10**7)
class LowLinks:
    def __init__(self, edges, edges_num:int):
        """edges[u]: all vertexes connected with vertex 'u'
        edges_num: number of edges of graph
        the root of DFS-tree is vertex 0
        """
        self.edges = edges
        self.V = len(edges)
        self.order = [-1]*V
        self.low = [float('inf')]*V
        self.bridges = []
        
        self.articulations = []
        if len(edges[0]) > 1 and edges_num == self.V-1:
            self.articulations.append(0)
        self.k = 0

    def build(self):
        self.dfs(0, 0)

    def get_bridges(self)->tuple:
        return self.bridges

    def get_articulations(self)->tuple:
        return self.articulations

    def dfs(self, v:int, prev:int):
        self.order[v] = self.k
        self.k += 1
        self.low[v] = self.order[v]
        is_articulation = False
        for to in self.edges[v]:
            if self.order[to] < 0: 
                self.dfs(to, v)
                self.low[v] = min(self.low[v], self.low[to])
                if self.low[v] < self.low[to]:
                    self.bridges.append((v, to))
                is_articulation |= self.order[v] <= self.low[to]
            elif to != prev:
                self.low[v] = min(self.low[v], self.order[to])
        if v>0 and is_articulation:
            self.articulations.append(v)

if __name__ == "__main__":
    V,E = map(int, readline().split())
    edges = [[] for _ in range(V)]
    for _ in range(E):
        s,t = map(int, readline().split())
        edges[s].append(t)
        edges[t].append(s)
    lowlinks = LowLinks(edges, E)
    lowlinks.build()
    articulations = lowlinks.get_articulations()
    if articulations:
        print(*sorted(articulations), sep="\n")

Solution (Python):
import sys
sys.setrecursionlimit(1000000)

def solve():
    graph = [[] for _ in range(v)]
    for i in range(e):
        graph[s[i]].append(t[i])
        graph[t[i]].append(s[i])
    
    used = [False for _ in range(v)]
    ord = [0 for _ in range(v)]
    low = [10**6 for _ in range(v)]
    is_articulation = [False for _ in range(v)]
    
    def rec(v, prev, k):
        if used[v]:
            return
        used[v] = True
        k = k+1
        ord[v] = k
        low[v] = ord[v]
        cnt = 0
        for u in graph[v]:
            if not used[u]:
                cnt += 1
                rec(u, v, k)
                low[v] = min(low[v], low[u])
                if prev >= 0 and ord[v] <= low[u]:
                    is_articulation[v] = True
            elif u != prev:
                low[v] = min(low[v], ord[u])
        if prev == -1 and cnt >= 2:
            is_articulation[v] = True
        
        return k
    
    rec(0, -1, 0)
    
    for i in range(v):
        if is_articulation[i]:
            print(i)

def input(f):
    global v, e
    global s, t
    
    v, e = map(int, f.readline().split())
    s = [-1 for _ in range(e)]
    t = [-1 for _ in range(e)]
    for i in range(e):
        s[i], t[i] = map(int, f.readline().split())

with open('/dev/stdin') as f:
    input(f)
    solve()