Approach (two parts): 1) static detection (articulation points & bridges) via Tarjan DFS; 2) support online edge insertions (only additions) with amortized near-constant updates using DSU-based 2-edge-connected-component maintenance.Static (Tarjan) — pseudocode:procedure Tarjan(G):
time = 0
for v in V:
if not visited[v]: dfs(v, parent=-1)
procedure dfs(v, parent):
visited[v]=true
tin[v]=low[v]=time; time++
children=0
for to in adj[v]:
if to==parent: continue
if visited[to]:
low[v]=min(low[v], tin[to])
else:
children++
dfs(to, v)
low[v]=min(low[v], low[to])
if low[to] > tin[v]: report bridge (v,to)
if parent!=-1 and low[to] >= tin[v]: report articulation v
if parent==-1 and children>1: report articulation v
Key: tin = discovery time, low = lowest reachable discovery time.Online edge insertions (only additions)Goal: maintain connectivity and detect whether an edge is a bridge after insertions. Use DSU for connected components (cc) and DSU for 2-edge-connected components (2ecc), plus parent pointers and an array "last_visit" for path compression. This is the standard amortized algorithm (cp-algorithms: online bridges).State:- dsu_cc.find(v): connected component leader- dsu_2ecc.find(v): 2-edge-connected component leader- parent[v]: tree-parent in the maintained forest- lca_iteration, last_visit[v]: used in merging paths- bridges: current number of bridgesPseudocode (sketch):initialize: for v in V: dsu_cc.make(v); dsu_2ecc.make(v); parent[v]=-1; last_visit[v]=0
lca_iteration=0; bridges=0
procedure make_root(v):
v = dsu_2ecc.find(v)
root = v
child = -1
while v != -1:
p = dsu_2ecc.find(parent[v]) if parent[v]!=-1 else -1
parent[v] = child
cc_leader = dsu_cc.find(v)
dsu_cc.union(root, cc_leader)
child = v
v = p
procedure merge_path(a, b):
lca_iteration++
path_a = []; path_b = []
while True:
if a!=-1:
a = dsu_2ecc.find(a)
path_a.append(a)
if last_visit[a]==lca_iteration: lca=a; break
last_visit[a]=lca_iteration
a = parent[a]
if b!=-1:
b = dsu_2ecc.find(b)
path_b.append(b)
if last_visit[b]==lca_iteration: lca=b; break
last_visit[b]=lca_iteration
b = parent[b]
for v in path_a until lca:
dsu_2ecc.union(v, lca); bridges -=1
for v in path_b until lca:
dsu_2ecc.union(v, lca); bridges -=1
procedure add_edge(a,b):
a = dsu_2ecc.find(a); b = dsu_2ecc.find(b)
if a==b: return
ca = dsu_cc.find(a); cb = dsu_cc.find(b)
if ca != cb:
bridges +=1
// link trees: make_root(a); parent[a]=b; dsu_cc.union(ca, cb)
make_root(a)
parent[a]=b
dsu_cc.union(ca, cb)
else:
// adding edge inside same connected component may merge 2-edge-comp along path
merge_path(a,b)
Key ideas and reasoning:- dsu_2ecc keeps nodes of same 2-edge-connected component compressed; merging reduces bridges along path.- make_root rearranges the maintained forest so linking is easy.- merge_path finds LCA via alternating upward walks with a visit stamp; then compresses path to the LCA, unioning 2ecc sets and decrementing bridges for each bridge removed.- bridges variable tracks number of bridge edges; checking whether an arbitrary edge is currently a bridge can be determined by whether its endpoints are in different 2eccs and whether it's the unique edge linking cc — queries can be answered in O(α(n)) via finds.Complexities and guarantees:- Each add_edge runs amortized O(α(n)) (nearly constant) due to path compressions and DSU union-by-rank with path compression; lca-finding uses visits that amortize across merges.- Connectivity query (are u and v connected): O(α(n)) via dsu_cc.find.- Is-edge-a-bridge (after insertion): O(α(n)) — check if endpoints are in different 2eccs and whether that edge is the unique connector (tracked via bridges count / structure).- Space: O(n + m_added).Notes and trade-offs:- This algorithm supports only edge additions. Full dynamic deletions require more complex data structures (ET-trees, Holm-de Lichtenberg-Thorup) with polylogarithmic bounds.- The online algorithm above is practical and simple to implement for production ML infra that needs to maintain connectivity/critical-edge info as new relationships (edges) appear in graphs (e.g., evolving data lineage, feature dependency graphs).