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
sys.setrecursionlimit(100000)

V,E = map(int, input().split())

A = [[] for i in range(V)]
for i in range(E):
    s,t = map(int, input().split())
    A[s].append(t)
    A[t].append(s)
     

prenum = [None for i in range(V)]

parent = [None for i in range(V)]

lowest = [None for i in range(V)]

visited = [False for i in range(V)]
 
def DFS(u = 0, prev = -1, timer = 0):
    prenum[u] = timer
    lowest[u] = timer
    timer += 1
    visited[u] = True
     
    for v in A[u]:
        if not visited[v]:
            parent[v] = u
            DFS(v, u, timer)
            lowest[u] = min(lowest[u], lowest[v])
        elif v != prev:
            lowest[u] = min(lowest[u], prenum[v])
DFS()
 
ans = set()
  
for u in range(1, V):
    p = parent[u]
    if prenum[p] <= lowest[u]:
        ans.add(p)
  
if parent.count(0) >= 2:
    ans.add(0)
else:
    ans.discard(0)
  
ans = list(ans)
ans.sort()
  
if ans:
    print(*ans, sep = '\n')

Solution (Python):
import sys

sys.setrecursionlimit(100000)

def dfs(v, tm):
    dts[v] = est[v] = tm + 1
    child = 0

    for i in adj[v]:
        if est[i] == float('inf'):
            child += 1
            parents[i] = v
            dfs(i, tm + 1)
            est[v] = min(est[v], est[i])

            if parents[v] is None and child > 1: aps[v] = True
            if parents[v] is not None and est[i] >= dts[v]: aps[v] = True

        elif parents[v] != i:
            est[v] = min(est[v], dts[i])


nv, ne = map(int, input().split(' '))
adj = [[] for _ in range(nv)]
est = [float('inf')] * nv
parents = [None] * nv
aps = [False] * nv
dts = [0] * nv

for _ in range(ne):
    s, t = map(int, input().split(' '))
    adj[s].append(t)
    adj[t].append(s)

dfs(0, 0)

for i in range(nv):
    if aps[i]:
        print(i)

Solution (Python):
from sys import stdin
import sys
from math import isinf
INF = float("inf")
sys.setrecursionlimit(100000)
def dfs(v, tm):
    dts[v] = est[v] = tm + 1
    child = 0
    for i in adj[v]:
        if isinf(est[i]):
            child += 1
            parents[i] = v
            dfs(i, tm + 1)
            est[v] = min(est[v], est[i])
            if parents[v] is None and child > 1: aps[v] = True
            if parents[v] is not None and est[i] >= dts[v]: aps[v] = True
        elif parents[v] != i:
            est[v] = min(est[v], dts[i])
n, m = map(int, stdin.readline().split())
adj = [[] for _ in range(n)]
est = [float('inf')] * n
parents = [None] * n
aps = [False] * n
dts = [0] * n
for _ in range(m):
    s, t = map(int, stdin.readline().split())
    adj[s].append(t)
    adj[t].append(s)
dfs(0, 0)
for i in range(n):
    if aps[i]:
        print(i)

Solution (Python):
from sys import stdin
import sys
from math import isinf
INF = float("inf")
sys.setrecursionlimit(100000)
def dfs(v, tm):
    dts[v] = est[v] = tm + 1
    child = 0
    for i in adj[v]:
        if est[i] == float('inf'):
            child += 1
            parents[i] = v
            dfs(i, tm + 1)
            est[v] = min(est[v], est[i])
            if parents[v] is None and child > 1: aps[v] = True
            if parents[v] is not None and est[i] >= dts[v]: aps[v] = True
        elif parents[v] != i:
            est[v] = min(est[v], dts[i])
n, m = map(int, stdin.readline().split())
adj = [[] for _ in range(n)]
est = [float('inf')] * n
parents = [None] * n
aps = [False] * n
dts = [0] * n
for _ in range(m):
    s, t = map(int, stdin.readline().split())
    adj[s].append(t)
    adj[t].append(s)
dfs(0, 0)
for i in range(n):
    if aps[i]:
        print(i)

Solution (Python):
import sys
from collections import defaultdict

sys.setrecursionlimit(2000000)

V, E = map(int, input().split())

Edges = defaultdict(set)

for i in range(E):
    s, t = map(int, input().split())
    Edges[s].add(t)
    Edges[t].add(s) 
    
preord = [None] * V 
parent = [None] * V 
lowlink = [None] * V
isVisited = [False] * V
counter = 0

def DFS(cur, prev):
    global counter
    preord[cur] = lowlink[cur] = counter
    isVisited[cur] = True
    counter += 1
    
    for edge in Edges[cur]: 
        if not isVisited[edge]: 
            parent[edge] = cur
            DFS(edge, cur)
            lowlink[cur] = min(lowlink[cur], lowlink[edge])
        elif edge != prev: 
                lowlink[cur] = min(lowlink[cur], preord[edge])
        
DFS(0,-1) 

art_point = [False] * V
r = 0

for _ in filter(lambda x: x == 0, parent):
    r += 1
    if r > 1:
        art_point[0] = True
        break

for i in range(1, V):
    p = parent[i]
    if p and preord[p] <= lowlink[i]:
        art_point[p] = True
 
for i, e in enumerate(art_point):
    if e: print(i)

Solution (Python):

from sys import setrecursionlimit
setrecursionlimit(100000)

def inpl(): return tuple(map(int, input().split()))

V, E = inpl()
graph = [[] for k in range(V)]

for _ in range(E):
    s, t = inpl()
    graph[s].append(t)
    graph[t].append(s)

prenum = [-1] * V
lowest = [float("inf")] * V
found = [False] * V
parent = [-1] * V

result = set()
root = 0

def DFS(i, c, prev):
    global root
    prenum[i] = c
    lowest[i] = c
    found[i] = True
    
    for p in graph[i]:
        if found[p]:
            if p != prev:
                lowest[i] = min(lowest[i], prenum[p])
        else:
            c = DFS(p, c+1, i)
            lowest[i] = min(lowest[i], lowest[p])
    
    if prenum[prev] <= lowest[i]:
        result.add(prev)
    parent[i] = prev
    
    return c
DFS(0, 1, 0)

if parent.count(0) <= 2:
    result = result.difference([0])

for r in sorted(result):
    print(r)

Solution (Python):
import sys
sys.setrecursionlimit(10**6)
def get_articulation_points(G, N, start=0):
    v_min = [0]*N; order = [None]*N
    result = []; count = 0
    def dfs(v, prev):
        nonlocal count
        r_min = order[v] = count
        fcnt = 0; p_art = 0
        count += 1
        for w in G[v]:
            if w == prev:
                continue
            if order[w] is None:
                ret = dfs(w, v)
                p_art |= (order[v] <= ret)
                r_min = min(r_min, ret)
                fcnt += 1
            else:
                r_min = min(r_min, order[w])
        p_art |= (r_min == order[v] and len(G[v]) > 1)
        if (prev == -1 and fcnt > 1) or (prev != -1 and p_art):
            result.append(v)
        return r_min
    dfs(start, -1)
    return result

n, m = map(int, input().split())
G = [[] for i in range(n)]
for i in range(m):
    s, t = map(int, input().split())
    G[s].append(t)
    G[t].append(s)
*_,=map(print,sorted(get_articulation_points(G, n)))

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 collections import defaultdict
import sys
sys.setrecursionlimit(100000)

def seq():
    a = 1
    while True:
        yield a
        a += 1

def dfs(here, went, connect, discovery, low, answer, seq):
    went |= {here}
    discovery[here] = low[here] = next(seq)
    child = 0
    for con in connect[here]:
        if con not in went:
            parent[con] = here
            child += 1
            dfs(con, went, connect, discovery, low, answer, seq)
            low[here] = min(low[here], low[con])
            if parent[here] is None and child >= 2:
                answer[here] = 1
            elif parent[here] is not None and discovery[here] <= low[con]:
                answer[here] = 1
        elif parent[here] != con:
            low[here] = min(low[here], discovery[con])

vertices, edges = (int(n) for n in input().split(" "))
connect = defaultdict(list)
for _ in range(edges):
    v1, v2 = (int(n) for n in input().split(" "))
    connect[v1].append(v2)
    connect[v2].append(v1)
answer = [0 for n in range(vertices)]
new_seq = seq()
went = set()
discovery = [0 for n in range(vertices)]
low = [float("inf") for n in range(vertices)]
parent = [None for n in range(vertices)]
dfs(0, went, connect, discovery, low, answer, new_seq)
for i,n in enumerate(answer):
    if n:
        print(i)

Solution (Python):
from collections import defaultdict
import sys
sys.setrecursionlimit(100*sys.getrecursionlimit())
V, E = map(int, input().split())
G = defaultdict(list)
T = defaultdict(list)
for i in range(E):
    s,t = map(int, input().split())
    G[s].append(t)
    G[t].append(s)

prenum = [float('inf')] * V
lowest = [float('inf')] * V
parent = [None] * V
visited = [False] * V

def dfs(g,s,c=0,p=None):    
    visited[s] = True
    prenum[s] = c
    lowest[s] = c
    c+=1    
    for v in g[s]:
        if not visited[v]:
            parent[v] = s
            T[v].append(s)
            T[s].append(v)
            dfs(g,v,c,s)
            lowest[s] = min( lowest[s], lowest[v] )
        elif v != p:
            lowest[s] = min( lowest[s], prenum[v] )

dfs(G,0)
k = []
if len(T[0]) > 1: k.append(0)
for u in range(V):
    p = parent[u]
    if p is None or p == 0: continue
    if prenum[p] <= lowest[u]: k.append(p)
for i in sorted(set(k)):
    print(i)

Solution (Python):


import sys
sys.setrecursionlimit(200000)


if __name__ == '__main__':

    n, m = [int(s) for s in input().split()]
    E = [set() for _ in range(n)]
    for _ in range(m):
        s, t = [int(s) for s in input().split(" ")]
        E[s].add(t)
        E[t].add(s)

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

        visited[current] = 1

        for v in E[current]:
            if visited[v] == 0:
                parent[v] = current
                dfs(v, current)
                lowest[current] = min(lowest[current], lowest[v])
            elif v != prev:  
                lowest[current] = min(lowest[current], prenum[v])

    prenum = [None] * n
    parent = [None] * n
    lowest = [float("inf")] * n
    timer = 1
    visited = [0] * n

    dfs(0, -1)

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

    if np > 1:
        ap.append(0)

    ap = list(set(ap))
    ap.sort()
    if ap:
        print("\n".join(map(str, ap)))

Solution (Python):
from math import inf
import sys
input = lambda: sys.stdin.readline().rstrip()
sys.setrecursionlimit(10**6)


def dfs(v,par):
    global cur
    vis[v]=1 ; disc[v]=cur ;low[v]=cur ; child=0 
    cur+=1
    for i in g[v]:
        if vis[i]==0:
            child+=1
            dfs(i,v)
            low[v]=min(low[i],low[v])
            if par==-1 and child>1:
                apts.add(v)
            if par!=-1 and low[i]>=disc[v]:
                apts.add(v)

        elif i!=par: low[v]=min(disc[i],low[v])
   
def articulation_pts():
    global apts,disc,low,vis
    disc=[0]*n ; low=[inf]*n ; vis=[0]*n ; par=[-1]*n ; apts=set()  
    for i in range(n):
        if vis[i]==0:
            dfs(i,-1)

n,e=map(int,input().split())
cur=0
g=[[] for i in range(n)]
for i in range(e):
    x,y=map(int,input().split())
    g[x].append(y)
    g[y].append(x)
articulation_pts()
apts=sorted(apts)
for i in apts:
    print(i)

Solution (Python):
from sys import stdin, setrecursionlimit
input = stdin.readline
setrecursionlimit(500*500) 

from collections import defaultdict, deque

infty = 2 ** 30

dic = defaultdict(lambda: [-1, infty])





lines = stdin.readlines()

v, e = map(int, lines[0].split())

glist = [[] for i in range(v)]
parent = [-1] * v
for i in range(e):
    s, t = map(int, lines[i+1].split())
    glist[s].append(t)
    glist[t].append(s)


t = 0
def depthFirstSearch(current, prev):
    global t
    t += 1
    dic[current][0] = t 
    if dic[current][1] > t:
        dic[current][1] = t
    for y in range(len(glist[current])):
        next = glist[current][y]
        if dic[next][0] == -1:
            parent[next] = current
            depthFirstSearch(next,current)
            if dic[current][1] > dic[next][1]:
                dic[current][1] = dic[next][1]
        elif next != prev:
            if dic[current][1] > dic[next][0]:
                dic[current][1] = dic[next][0]
    return

def art_points():
    
    depthFirstSearch(0, -1)
    np = 0
    ap = set()
    for i in range(1, v):
        p = parent[i]
        if p == 0:
            np += 1
        elif dic[p][0] <= dic[i][1]:
            ap.add(p)
    if np > 1:
        ap.add(0)

    ap = sorted(list(ap))
    for i in range(len(ap)):
        print(ap[i])

art_points()

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

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

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


def solve():
    
    used = [False for _ in range(v)]
    ord = [0 for _ in range(v)]
    low = [float("inf") for _ in range(v)]
    is_articulation = [False for _ in range(v)]
    
    def dfs(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 G[v]:
            if not used[u]:
                cnt += 1
                dfs(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
    
    dfs(0, -1, 0)
    
    for i in range(v):
        if is_articulation[i]:
            print(i)

solve()

Solution (Python):


import sys
sys.setrecursionlimit(100000)
from collections import defaultdict





class Graph:

    def __init__(self, vertices):
        self.V = vertices  
        self.graph = defaultdict(list)  
        self.Time = 0

    
    def addEdge(self, u, v):
        self.graph[u].append(v)
        self.graph[v].append(u)

        '''A recursive function that find articulation points
        using DFS traversal
        u --> The vertex to be visited next
        visited[] --> keeps tract of visited vertices
        disc[] --> Stores discovery times of visited vertices
        parent[] --> Stores parent vertices in DFS tree
        ap[] --> Store articulation points'''

    def APUtil(self, u, visited, ap, parent, low, disc):
        
        children = 0

        
        visited[u] = True

        
        disc[u] = self.Time
        low[u] = self.Time
        self.Time += 1

        
        for v in self.graph[u]:
            
            
            if visited[v] == False:
                parent[v] = u
                children += 1
                self.APUtil(v, visited, ap, parent, low, disc)

                
                
                low[u] = min(low[u], low[v])

                
                
                if parent[u] == -1 and children > 1:
                    ap[u] = True

                
                
                if parent[u] != -1 and low[v] >= disc[u]:
                    ap[u] = True

                
            elif v != parent[u]:
                low[u] = min(low[u], disc[v])

    
    def AP(self):

        
        
        
        visited = [False] * (self.V)
        disc = [float("Inf")] * (self.V)
        low = [float("Inf")] * (self.V)
        parent = [-1] * (self.V)
        ap = [False] * (self.V)  

        
        
        
        for i in range(self.V):
            if visited[i] == False:
                self.APUtil(i, visited, ap, parent, low, disc)
        for index, value in enumerate(ap):
            if value == True:
                print(index)


def main():
    V, E = map(int, input().split())
    G = Graph(V)
    for _ in range(E):
        s, t = map(int, input().split())
        G.addEdge(s, t)

    G.AP()




if __name__ == "__main__":
    main()

Solution (Python):
import sys
sys.setrecursionlimit(10000000)
MOD = 10 ** 9 + 7
INF = 10 ** 15

class LowLink():
    def __init__(self,G):
        self.N = len(G)
        self.G = G
        self.low = [-1] * self.N
        self.ord = [-1] * self.N
    
    def _dfs(self,v,time,p = -1):
        self.ord[v] = self.low[v] = time
        time += 1

        isArticulation = False
        cnt = 0
        for e in self.G[v]:
            if self.low[e] < 0:
                cnt += 1
                self._dfs(e,time,v)
                self.low[v] = min(self.low[v],self.low[e])
                if p != -1 and self.ord[v] <= self.low[e]:
                    isArticulation = True
                if self.ord[v] < self.low[e]:
                    self.bridge.append((v,e))
            elif e != p:
                self.low[v] = min(self.low[v],self.ord[e])
        
        if p == -1 and cnt >= 2:
            isArticulation = True
        if isArticulation:
            self.articulation.append(v) 

    def build(self):
        self.articulation = []
        self.bridge = []
        self._dfs(0,0)
    

def main():
    V,E = map(int,input().split())
    G = [[] for _ in range(V)]
    for _ in range(E):
        a,b = map(int,input().split())
        G[a].append(b)
        G[b].append(a)
    
    lowlink = LowLink(G)
    lowlink.build()
    ans = lowlink.articulation
    ans.sort()
    if ans:
        print('\n'.join(map(str,ans)))
if __name__ == '__main__':
    main()

Solution (Python):
from sys import stdin, stdout
from collections import defaultdict
def readcase(o):
    line = o.readline()
    if not line: return None, None
    line = line.strip().split()
    
    

    return int(line[0]), int(line[1])

def tarjan(g):
    sources = list(g.keys())
    
    artPoints = set()
    time = {}
    low = {}
    parent = {}
    
    children = defaultdict(set)
    visitedTime = defaultdict(int)
    ti=0


    def dfs(u, stack):
        nonlocal ti
        while stack:
            u = stack[-1]
            visitedTime[u]+=1
            
            if u not in time:
                time[u] = ti
                low[u] = ti
                ti += 1 
            currChildren = 0
            for v in g[u]: 
                if v not in time: 
                    parent[v]=u
                    children[u].add(v)
                    currChildren+=1
                    stack.append(v)
                    break
                if v in children[u]:
                    low[u] = min(low[u], low[v]) 
                    if u in parent and low[v] >= time[u]:
                        artPoints.add(u)
                        
                    if u not in parent and len(children[u])>1:
                        artPoints.add(u)
                        
                elif u not in parent or parent[u] != v:
                    low[u] = min(low[u], time[v]) 
            if currChildren == 0:
                stack.pop()
    for s in sources:
        if s not in time:
            stack = [s]
            dfs(s, stack)
            ti=0
    ans = sorted(list(artPoints))
    for i, a in enumerate(ans):
        print(a)

if __name__ == '__main__':
    g = defaultdict(list)
    solutions = None
    u, v = readcase(stdin)
    if not (not u or u == 0):
        while 1:   
            u, v = readcase(stdin)
            if u == None:
                break
            if u != v:
                g[u].append(v)
                g[v].append(u)


        tarjan(g)

Solution (Python):
"""
8 10
0 1
1 2
0 2
0 3
3 2
3 4
3 5
5 6
5 7
6 7
"""
import sys
sys.setrecursionlimit(100000)
V,E = map(int,input().split())
C = [[] for _ in range(V)]
for i in range(E):
    tmp = list(map(int,input().split()))
    C[tmp[0]].append(tmp[1])
    C[tmp[1]].append(tmp[0])

INF = 10000000
visited = [False]*V
visit_cnt = 1
prenum = [0]*V
parent = [-1]*V
lowest = [INF]*V

def DFS(node):
    visited[node] = True
    global visit_cnt
    prenum[node] = visit_cnt
    visit_cnt += 1
    for adj in C[node]:
        if not visited[adj]:
            parent[adj] = node
            DFS(adj)

    node_lowest = prenum[node]
    for adj in C[node]:
        if adj != parent[node] and parent[adj] != node:
            if  prenum[adj] < node_lowest:
                node_lowest = prenum[adj]
        else:
            if parent[adj] == node and lowest[adj] < node_lowest:
                node_lowest = lowest[adj]
    lowest[node] = node_lowest
        
root = 0
DFS(root)
ans = []

root_cnt = 0
for p in parent:
    if p == root:
        root_cnt += 1
if root_cnt > 1:
    ans.append(root)

for node in range(V):
    if parent[node] != root and node != root:
        if prenum[parent[node]] <= lowest[node]:
            ans.append(parent[node])
ans = set(ans)
ans = list(ans)
ans.sort()
for i in ans:
    print(i)

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

V, E = list(map(int, input().split()))
G = [[] for i in range(V)]

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

class LowLink:
    def main(G, V):
        LowLink.G = G
        LowLink.used = [False] * V
        LowLink.ord = [0] * V
        LowLink.low = [0] * V
        LowLink.aps = []
        LowLink.bridges = []
        n = 0
        
        for i in range(V):
            if not LowLink.used[i]: n = LowLink.dfs(i, n, -1)
            
        LowLink.aps.sort()
        LowLink.bridges.sort()
        
    def dfs(v, n, par):
        LowLink.used[v] = True
        LowLink.ord[v] = n+1
        n += 1
        LowLink.low[v] = LowLink.ord[v]
        
        is_aps = False
        chi = 0
        
        for u in LowLink.G[v]:
            if not LowLink.used[u]:
                chi += 1
                n = LowLink.dfs(u, n, v)
                LowLink.low[v] = min(LowLink.low[v], LowLink.low[u])
                if par != -1 and LowLink.ord[v] <= LowLink.low[u]: is_aps = True
                if LowLink.ord[v] < LowLink.low[u]: LowLink.bridges.append((min(v, u), max(v, u)))
                
            elif u != par:
                LowLink.low[v] = min(LowLink.low[v], LowLink.ord[u])
                
        if par == -1 and chi >= 2: is_aps = True
        if is_aps: LowLink.aps.append(v)

        return n

LowLink.main(G, V)      

for v in LowLink.aps:
    print(v)

Solution (Python):
class Graph(): 
    def __init__(self,n,edge):
        self.n = n
        self.graph = [[] for _ in range(n)]
        self.deg = [0 for _ in range(n)]
        for e in edge:
            self.graph[e[0]].append(e[1])
            self.graph[e[1]].append(e[0])
            self.deg[e[0]] += 1
            self.deg[e[1]] += 1

    def lowlink(self): 
        self.ord = [None for _ in range(self.n)]
        self.low = [None for _ in range(self.n)]
        self.group = [None for _ in range(self.n)]
        self.prev = [None for _ in range(self.n)]
        self.tree = [[] for _ in range(self.n)]
        self.sorted = []
        order = 0
        count = 0
        low = [None for _ in range(self.n)]
        for s in range(self.n):
            if self.group[s] is None:
                stack = [(s, None)]
                while stack:
                    node, par = stack.pop()
                    if self.group[node] is None:
                        self.group[node] = count
                        self.ord[node] = order
                        self.sorted.append(node)
                        order += 1
                        if par is not None:
                            self.prev[node] = par
                            self.tree[par].append(node)
                        for adj in self.graph[node]:
                            if self.group[adj] is None:
                                stack.append((adj, node))
                count += 1
        for node in self.sorted[::-1]:
            self.low[node] = self.ord[node]
            for adj in self.graph[node]:
                if self.prev[adj]  == node:
                    self.low[node] = min(self.low[node], self.low[adj])
                elif self.prev[node] == adj:
                    continue
                else:
                    self.low[node] = min(self.low[node], self.ord[adj])

    def articulation(self):
        res = []
        for node in range(self.n):
            if self.prev[node] is None and len(self.tree[node]) > 1:
                res.append(node)
            if self.prev[node] is not None:
                for adj in self.tree[node]:
                    if self.ord[node] <= self.low[adj]:
                        res.append(node)
                        break
        return res

import sys
input = sys.stdin.readline

N, M = map(int, input().split())
E = [tuple(map(int, input().split())) for _ in range(M)]

g = Graph(N, E)
g.lowlink()
res = g.articulation()
if res:
    print('\n'.join(map(str, res)))

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

N, M = map(int, input().split())
G = [[] for _ in [0]*N]
for _ in [0]*M:
    a, b = map(int, input().split())

    G[a].append(b)
    G[b].append(a)

INF = 10**10
pre = [0]*N
visited = [0]*N
min_x = [INF]*N
is_articulation = [0]*N
n_root_children = 0


def dfs(v=0, p=-1, k=0):
    global n_root_children
    pre[v] = min_x[v] = mn = k
    visited[v] = 1

    for u in G[v]:
        if u == p:
            continue
        elif visited[u]:
            x = min_x[u]
            if x < mn:
                mn = x
            continue

        if v == 0:
            n_root_children += 1

        k += 1
        x = dfs(u, v, k)

        if pre[v] <= x:
            is_articulation[v] = 1
        if x < mn:
            mn = x

    min_x[v] = mn
    return mn


dfs()

for v, a in enumerate(is_articulation):
    if v == 0:
        if n_root_children >= 2:
            print(v)
    elif a:
        print(v)

Solution (Python):
import sys

sys.setrecursionlimit(10**6)

INF = 100000 + 1
V, E = map(int, input().split())
G = [[] * V for _ in range(V)]
visited = [False] * V
prenum = [INF] * V
parent = [INF] * V
lowest = [INF] * V
timer = 1

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

def dfs(cur, prv):
    global timer
    prenum[cur] = lowest[cur] = timer
    timer += 1
    visited[cur] = True
    for nxt in G[cur]:
        if not visited[nxt]:
            parent[nxt] = cur
            dfs(nxt, cur)
            lowest[cur] = min(lowest[cur], lowest[nxt])
        elif nxt != prv:
            lowest[cur] = min(lowest[cur], prenum[nxt])

dfs(0, -1)

np = 0
ap = []
for i in range(V):
    p = parent[i]
    if p == 0:
        np += 1
    elif p != INF and prenum[p] <= lowest[i]:
        ap.append(p)

if np > 1:
    ap.insert(0, 0)

for ans in sorted(set(ap)):
    print(ans)

Solution (Python):









import sys,collections
sys.setrecursionlimit(100000)
V,E = tuple(map(int,sys.stdin.readline().split())) 

INF = float("inf")

st = tuple(tuple(map(int,sys.stdin.readline().rstrip().split())) for _ in range(E)) 

G = [[] for _ in range(V)]

for s,t in st:
    G[s].append(t)
    G[t].append(s)

visited = set()
prenum = [0]*V
parent = [0]*V
lowest = [0]*V
timer = 0

def dfs(current,prev):
    global timer
    parent[current]=prev
    prenum[current]=lowest[current]=timer
    timer += 1
    visited.add(current)
    for nex in G[current]:
        if not nex in visited:
            dfs(nex,current)
            lowest[current]=min(lowest[current],lowest[nex])
        elif nex != prev:
            lowest[current]=min(lowest[current],prenum[nex])
dfs(0,-1)

ret = set()
if sum(1 for p in parent if p==0) > 1:
    ret.add(0)

for i in range(1,V):
    p = parent[i]
    if p != 0 and prenum[p] <= lowest[i]:
        ret.add(p)
ret = sorted(list(ret))

if ret:
    print(*ret,sep='\n')

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


def lowLink(N: int, Adj: list):
	articulation = []
	bridge = []
	order = [None] * N
	lowest = [1 << 100] * N

	def _dfs(cur, pre, k):
		order[cur] = lowest[cur] = k
		is_articulation = False
		cnt = 0
		for nxt in Adj[cur]:
			if order[nxt] is None:
				cnt += 1
				_dfs(nxt, cur, k + 1)
				if lowest[cur] > lowest[nxt]:
					lowest[cur] = lowest[nxt]
				is_articulation |= pre >= 0 and lowest[nxt] >= order[cur]
				if order[cur] < lowest[nxt]:
					bridge.append((cur, nxt))
			elif nxt != pre and lowest[cur] > order[nxt]:
				lowest[cur] = order[nxt]
		is_articulation |= pre < 0 and cnt > 1
		if is_articulation:
			articulation.append(cur)

	_dfs(0, -1, 0)
	return articulation, bridge


def main():
	n, m, *L = map(int, open(0).read().split())
	adj = [[] for _ in range(n)]
	for s, t in zip(*[iter(L)] * 2):
		adj[s] += t,
		adj[t] += s,
	articulation, _ = lowLink(n, adj)
	if articulation:
		print("\n".join(map(str, sorted(articulation))))


if __name__ == '__main__':
	main()