# Algoritmo de Tarjan para encontrar PUNTOS DE ARTICULACIÓN en un grafo no dirigido.
# Un "punto de articulación" es un vértice cuya eliminación incrementa
# el número de componentes conexas del grafo.
# ---------- Entrada y construcción del grafo ----------
n, m = map(int, input("Ingrese n (nodos) y m (aristas): ").split())
# Lista de adyacencia (indexada desde 1)
out = [[] for _ in range(n + 1)]
for _ in range(m):
a, b = map(int, input().split())
out[a].append(b)
out[b].append(a) # grafo no dirigido
# ---------- Inicialización de estructuras ----------
marked = [False] * (n + 1) # nodos visitados
depth = [0] * (n + 1) # profundidad del nodo en el árbol DFS
up = [0] * (n + 1) # menor profundidad alcanzable desde el subárbol
# ---------- DFS para detectar puntos de articulación ----------
def dfs(v, p):
marked[v] = True
up[v] = depth[v]
children = 0 # cantidad de hijos directos en el árbol DFS
for u in out[v]:
if u == p:
continue
elif marked[u]:
# Back edge
up[v] = min(up[v], depth[u])
else:
# Arista de árbol
depth[u] = depth[v] + 1
dfs(u, v)
up[v] = min(up[v], up[u])
# Si el subárbol de u no puede alcanzar un ancestro de v,
# entonces v es un punto de articulación
if up[u] >= depth[v] and p != -1:
print(v, "es punto de articulacion")
children += 1
# Caso especial: si v es raíz del DFS y tiene más de un hijo, es articulación
if p == -1 and children > 1:
print(v, "es punto de articulacion")
# ---------- Ejecutar DFS (en caso de grafo no conexo) ----------
for i in range(1, n + 1):
if not marked[i]:
depth[i] = 0
dfs(i, -1)
IyBBbGdvcml0bW8gZGUgVGFyamFuIHBhcmEgZW5jb250cmFyIFBVTlRPUyBERSBBUlRJQ1VMQUNJw5NOIGVuIHVuIGdyYWZvIG5vIGRpcmlnaWRvLgojIFVuICJwdW50byBkZSBhcnRpY3VsYWNpw7NuIiBlcyB1biB2w6lydGljZSBjdXlhIGVsaW1pbmFjacOzbiBpbmNyZW1lbnRhCiMgZWwgbsO6bWVybyBkZSBjb21wb25lbnRlcyBjb25leGFzIGRlbCBncmFmby4KCiMgLS0tLS0tLS0tLSBFbnRyYWRhIHkgY29uc3RydWNjacOzbiBkZWwgZ3JhZm8gLS0tLS0tLS0tLQpuLCBtID0gbWFwKGludCwgaW5wdXQoIkluZ3Jlc2UgbiAobm9kb3MpIHkgbSAoYXJpc3Rhcyk6ICIpLnNwbGl0KCkpCgojIExpc3RhIGRlIGFkeWFjZW5jaWEgKGluZGV4YWRhIGRlc2RlIDEpCm91dCA9IFtbXSBmb3IgXyBpbiByYW5nZShuICsgMSldCgpmb3IgXyBpbiByYW5nZShtKToKICAgIGEsIGIgPSBtYXAoaW50LCBpbnB1dCgpLnNwbGl0KCkpCiAgICBvdXRbYV0uYXBwZW5kKGIpCiAgICBvdXRbYl0uYXBwZW5kKGEpICAjIGdyYWZvIG5vIGRpcmlnaWRvCgojIC0tLS0tLS0tLS0gSW5pY2lhbGl6YWNpw7NuIGRlIGVzdHJ1Y3R1cmFzIC0tLS0tLS0tLS0KbWFya2VkID0gW0ZhbHNlXSAqIChuICsgMSkgICMgbm9kb3MgdmlzaXRhZG9zCmRlcHRoID0gWzBdICogKG4gKyAxKSAgICAgICAjIHByb2Z1bmRpZGFkIGRlbCBub2RvIGVuIGVsIMOhcmJvbCBERlMKdXAgPSBbMF0gKiAobiArIDEpICAgICAgICAgICMgbWVub3IgcHJvZnVuZGlkYWQgYWxjYW56YWJsZSBkZXNkZSBlbCBzdWLDoXJib2wKCiMgLS0tLS0tLS0tLSBERlMgcGFyYSBkZXRlY3RhciBwdW50b3MgZGUgYXJ0aWN1bGFjacOzbiAtLS0tLS0tLS0tCmRlZiBkZnModiwgcCk6CiAgICBtYXJrZWRbdl0gPSBUcnVlCiAgICB1cFt2XSA9IGRlcHRoW3ZdCiAgICBjaGlsZHJlbiA9IDAgICMgY2FudGlkYWQgZGUgaGlqb3MgZGlyZWN0b3MgZW4gZWwgw6FyYm9sIERGUwogICAgCiAgICBmb3IgdSBpbiBvdXRbdl06CiAgICAgICAgaWYgdSA9PSBwOgogICAgICAgICAgICBjb250aW51ZQogICAgICAgIGVsaWYgbWFya2VkW3VdOgogICAgICAgICAgICAjIEJhY2sgZWRnZQogICAgICAgICAgICB1cFt2XSA9IG1pbih1cFt2XSwgZGVwdGhbdV0pCiAgICAgICAgZWxzZToKICAgICAgICAgICAgIyBBcmlzdGEgZGUgw6FyYm9sCiAgICAgICAgICAgIGRlcHRoW3VdID0gZGVwdGhbdl0gKyAxCiAgICAgICAgICAgIGRmcyh1LCB2KQogICAgICAgICAgICB1cFt2XSA9IG1pbih1cFt2XSwgdXBbdV0pCiAgICAgICAgICAgIAogICAgICAgICAgICAjIFNpIGVsIHN1YsOhcmJvbCBkZSB1IG5vIHB1ZWRlIGFsY2FuemFyIHVuIGFuY2VzdHJvIGRlIHYsCiAgICAgICAgICAgICMgZW50b25jZXMgdiBlcyB1biBwdW50byBkZSBhcnRpY3VsYWNpw7NuCiAgICAgICAgICAgIGlmIHVwW3VdID49IGRlcHRoW3ZdIGFuZCBwICE9IC0xOgoJICAgICAgICAgICAgcHJpbnQodiwgImVzIHB1bnRvIGRlIGFydGljdWxhY2lvbiIpCiAgICAgICAgICAgIAogICAgICAgICAgICBjaGlsZHJlbiArPSAxCiAgICAKICAgICMgQ2FzbyBlc3BlY2lhbDogc2kgdiBlcyByYcOteiBkZWwgREZTIHkgdGllbmUgbcOhcyBkZSB1biBoaWpvLCBlcyBhcnRpY3VsYWNpw7NuCiAgICBpZiBwID09IC0xIGFuZCBjaGlsZHJlbiA+IDE6CiAgICAgICAgcHJpbnQodiwgImVzIHB1bnRvIGRlIGFydGljdWxhY2lvbiIpCgoKIyAtLS0tLS0tLS0tIEVqZWN1dGFyIERGUyAoZW4gY2FzbyBkZSBncmFmbyBubyBjb25leG8pIC0tLS0tLS0tLS0KZm9yIGkgaW4gcmFuZ2UoMSwgbiArIDEpOgogICAgaWYgbm90IG1hcmtlZFtpXToKICAgICAgICBkZXB0aFtpXSA9IDAKICAgICAgICBkZnMoaSwgLTEpCg==