### Mythic07's blog

By Mythic07, history, 4 weeks ago,

In a recent Online assessment, i got this beautiful problem.

We are given a connected undirected graph. We have to find the number of triplets i, j and k (i != j != k) such that: on removing vertex j from the graph, vertex i and k becomes unreachable from each other.

1 <= n <= 1e5 (vertices) 1 <= m <= 1e5 (edgee)

We're supposed to utilize the concept of articulation points and 2-vertex-connected components. But couldn't deduce any proper solution.

• -6

 » 4 weeks ago, # | ← Rev. 2 →   0 Any j that disconnects things must be an articulation point (by definition of articulation point). Given an articulation point j, then i and k must be on "different sides" of j.A way to formalize this idea of "different sides" could be using biconnected components and the block-cut tree. But I think this is overkill.For any i and k that are in "the same side" of j, they will be in the same subtree of j in the DFS tree (or in none, if the path to both involves moving to the parent of j).Therefore, for each articulation point j we want to count all pairs of nodes (i,k) that are across it. I'd use DP over the DFS tree. The simplest formula in my opinion would be to count all pairs of nodes and then remove the ones that don't cross over j. # g is an adjacency list that only contains directed forward-edges def compute(u): ans = 0 for v in g[u]: ans += compute(v) if is_articulation[u]: # initially say all pairs of nodes cross u ans += choose(n-1, 2) # remove pairs within "upwards subtree" ans -= choose(n - subtree_size[u], 2) for v in g[u]: # remove pairs within each child subtree ans -= choose(subtree_size[v], 2) return ans 
•  » » 4 weeks ago, # ^ |   0 I did the exact same thing. But if fails on the following graph. 6 and 5 will always lie in 2 different branches of the tree, but they have to be in the same. (or maybe I'm wrong about the decomposition, if so can you please mention some resource?, I've encountered this type of problem, a number of times)
•  » » » 4 weeks ago, # ^ | ← Rev. 2 →   0 You are absolutely right. A DFS tree rooted from node 4 will end up with 6 and 5 on different sides of 7. Alright, it's a bit more annoying then.The problem is that an articulation point can have multiple children that are in the same biconnected component. So let's condense every biconnected component into a single node, while keeping articulation points intact. This is known as the block-cut tree of a graph.Now the problem is gone, so the previous solution works with a little adjustment.The only difference is that instead of using literal subtree sizes, we use the sizes in the original graph (each biconnected component adds size equal to its number of non-articulation-point elements) # g is the adjacency list of a rooting of the block-cut tree (only forward edges) ans = 0 for u in articulation_points: ans += choose(n - 1, 2) # all pairs ans -= choose(n - subtree_size[u], 2) # remove pairs "above" u for v in g: ans -= choose(subtree_size[v], 2) # remove pairs "below" u 
•  » » » » 4 weeks ago, # ^ | ← Rev. 2 →   0 Thanks, I'll read about block-cut tree and will try to implement.
 » 4 weeks ago, # |   0 I was thinking that you get all the cycles and their lengths, and then do for each cycle length add this to the running sum: n-CycleLengthI'm not sure if this is correct, but it's the first thing that comes to my mind.
•  » » 4 weeks ago, # ^ |   0 didn't get your point. What's the use of cycle lengths?? And, anyways finding all cycles is i guess NP
•  » » » 4 weeks ago, # ^ |   0 It seems like it is O(n) to find cycle lengths. My idea was anything that isn't in the same cycle, then there is a way to split them.Now that I think about it, it might not work. I forgot a case.