Graphs · Hard

398. Oliver and the Game

Topics: Graph, Queue

Solve it on DeVert Campus - free code runner

Problem

Oliver moves around an undirected connected graph with n vertices (0-indexed) and m edges. For each of q queries, given three distinct vertices a, b, c, determine whether c blocks every possible path from a to b - that is, whether every path between a and b passes through c. Print 'Yes' or 'No' for each query, one per line.

Input and output

Input: The first line contains n, the number of vertices. The second line contains m, the number of edges. Each of the next m lines contains two integers, an undirected edge. This is followed by a line with q, the number of queries, then q lines each containing three integers a b c. Output: Print 'Yes' or 'No' for each query, one per line, indicating whether c lies on every path between a and b.

Example

Input:
5
4
0 1
1 2
2 3
3 4
2
0 4 2
0 2 1
Output:
Yes
Yes

Constraints

1 <= n <= 1000, 1 <= q <= 1000

Key observation

This connects directly to the concept of 'cut vertices' (articulation points) from graph theory - c blocking every a-to-b path is a PAIR-SPECIFIC version of the more general 'is c a cut vertex for the WHOLE graph' question, checked here per query rather than globally.

Intuition

For each query, check whether every path between two vertices must pass through a given third vertex. Brute force: Try to enumerate every possible path between a and b directly and check if all of them pass through c - this could be exponential in the number of paths for a densely connected graph, when a single removal-and-reachability check answers the question directly. Optimised: Since 'c blocks every path' is mathematically equivalent to 'removing c disconnects a from b', a SINGLE BFS/DFS after temporarily removing c directly answers each query - no need to enumerate or reason about paths explicitly at all, just check simple reachability in the modified graph.

Approach 1

For each query (a, b, c), remove vertex c and all of its incident edges from the graph entirely, then run a BFS or DFS from a to check whether b is still reachable. c blocks every a-b path exactly when a and b land in different components of this reduced graph, which is a direct implementation of the problem's definition, but it re-traverses the whole graph once per query. Time: O(q*(n+m)) Space: O(n+m)

Optimal - Block-Cut Tree with LCA

Build the block-cut tree of the graph in a single DFS, where biconnected components and articulation points both become tree nodes connecting the blocks they belong to. A vertex c separates a and b exactly when c is an articulation point that lies on the unique path between a's and b's positions in this tree, a standard fact about block-cut trees. Root the tree and preprocess it for LCA queries (e.g., binary lifting); each query is then answered by testing, via ancestor checks against the LCA, whether c's tree node lies on the path between a's and b's tree nodes. Time: O((n+m) log n) Space: O(n+m)

Better - Articulation Point Pre-check

First run Tarjan's articulation point algorithm once over the whole graph, a single DFS tracking discovery times and low-link values, to know up front which vertices are cut vertices at all. If c is not a cut vertex, it's structurally impossible for it to lie on every a-b path, so the query can be answered 'No' immediately without touching the graph. Only for queries where c actually is an articulation point does the algorithm fall back to removing c and checking connectivity via BFS/DFS, which prunes away most negative queries cheaply after one preprocessing pass. Time: O(n+m + q*(n+m)) Space: O(n+m)

Step by step

1. Recognize that 'every path from a to b passes through c' is EXACTLY the definition of c being a CUT VERTEX separating a from b. 2. For each query, TEMPORARILY remove vertex c (skip it and every edge touching it), then run BFS/DFS from a. 3. If b is NO LONGER reachable, c was blocking every path; if b is still reachable, some path avoided c entirely.

Complexity

Time: O(q * (n + m)) - each of the q queries requires one fresh BFS/DFS pass over the graph (minus the removed vertex). Space: O(n + m), for the graph representation and visited tracking, reused across queries.

Edge cases

Test c directly adjacent to a or b, a query where removing c doesn't disconnect a from b (expect 'No'), and q at its upper bound of 1000, which requires each query's check to be efficient.

Interview tip

Be ready to explain WHY doing a fresh removal-and-check per query (rather than trying to precompute something universal) is the right approach here - a vertex c that blocks paths between one specific pair (a,b) might NOT block paths between a different pair, so no single universal precomputation captures all query answers at once.

All DSA problems