This is a surprisingly elegant ICPC problem that happens to be in the official codeforces problemset.
Problem CF-2068E
Statement
FC Porto and SL Benfica are the two largest football teams in Portugal. Naturally, when the two play each other, a lot of people travel from all over the country to watch the game. This includes the Benfica supporters' club, which is going to travel from Lisbon to Porto to watch the upcoming game. To avoid tensions between them and the Porto supporters' club, the national police want to delay their arrival to Porto as much as they can.
The road network in Portugal can be modelled as a simple, undirected, unweighted, connected graph with
vertices and edges, where vertices represent towns and edges represent roads. Vertex 1 corresponds to Lisbon, i.e., the starting vertex of the supporters' club, and vertex is Porto, i.e., the destination vertex of the supporters' club. The supporters' club wants to minimize the number of roads they take to reach Porto. The police are following the supporters' club carefully, and so they always know where they are. To delay their arrival, at any point the police can pick exactly one road and block it, as long as the supporters' club isn't currently traversing it. They can do this exactly once, and once they do that, the road is blocked forever. Once the police block a road, the supporters' club immediately learns that that road is blocked, and they can change their route however they prefer. Furthermore, the supporters' club knows that the police are planning on blocking some road and can plan their route accordingly.
Assuming that both the supporters' club and the police always make optimal choices, determine the minimum number of roads the supporters' club needs to traverse to go from Lisbon to Porto. If the police can block the supporters' club from ever reaching Porto, then output −1.
Constraints:
Solution
I'll refer to the party traversing the graph from
Let's try to think of optimal strategies for
When trying to analyse the situation by mentally simulating some naive strategies, one runs into a sort of "chicken and egg" problem that is common in game-theoretic problems like these - the optimal move for
Consider a naive strategy: What if
Now consider the following graph:

If
However, if we go down the lower path instead,
- Delete edge
after traverses the edge . then takes the path . - If
doesn't do the above, then traverses the edge and deletes the edge . then goes to via .
So the "always follow the shortest path" strategy is clearly not optimal for
Notice that if
Some more definitions:
- the graph we operate upon. shortest distance between the nodes and in the graph .
Now, can we compute
There are two branches, based on what
deletes some edge right after we reach . Which edge would delete in this case? Some edge that maximises . stalls and decides to delete an edge later. In this case, simply moves to , and we have .
We therefore have:
The first term in the outermost max is clearly problematic, as it requires the consideration of way too many edges, along with a computationally unfriendly function (shortest path from a source after the deletion of an edge), so let's think a bit more about the edges we may need to delete.
Clearly, the optimal edge
So if there's no common edge shared between all shortest paths, we need not bother with the first term, but what if there is? Trying to optimally choose one ends up being rather cancerous once you think about it, and no sub-linear way presents itself quickly.
Notice that while trying to prune the set of potentially deleted edges
What if
The intuitive hope is that deleting later leads to a longer path due to

Upon some further thought, one realizes that it's never optimal to delete some edge
Proof
Let's say
- If at some point of time in the future,
reaches (or WLOG ), deletes immediately afterwards. then goes from to . This leads to it taking a path (which necessarily doesn't include the edge ), which is at least as long as any path it could have taken from to without the edge if deleted the edge immediately after it reaching . - Otherwise, if
never even visits (or ) in the future, then deleting wouldn't have been (strictly) optimal in the first place.
So we now know that if
Define
Since this seems like a standard subproblem, let's assume that we know how to solve this for now, and return to the expression:
Clearly, values in
precompute f[n]
initialize t[n] with t[i] = inf
t[n] = 0
set<pair<int, int>> q
q.push({t[n], n})
while(!q.empty()):
int u = (*q.begin()).second
q.erase(q.begin())
for v in adj[u]:
nx = max(1 + t[u], f[v])
if(nx < tv):
q.erase({t[v], v})
t[v] = nx
q.insert({t[v], v})
ans = t[1]
Let's return to the subproblem we assumed to be solvable earlier. We consider the BFS-DAG of the given graph assuming the source to be
Definition of the BFS-DAG
Then, it's easy to see that for every edge
Characterization of edges:
: cross edge : back edge : forward edge
Here's an accompanying visual:

Notice that:
- If some node
has multiple back-edges , then (for example, in the given image). - If a node
has only one back-edge but has some cross-edge , then (for example, in the given image).
Let's consider the complement of the above two cases: we have a node
- We travel down to some node
(reachable from ) such that has a cross-edge or back-edge such that isn't reachable from . - We take the back/cross-edge and then go from
to .
This path will have a length of
This implies that it's optimal to go to nodes with the lowest levels with such back/cross edges, and then prefer back-edges over cross-edges amongst these nodes.
Now, we don't really need to make any further simplifications as this sub-problem can be solved with some ugly small-to-large merging, but we can simplify it by a great deal.
Let's consider the BFS-Tree instead (a sub-graph of the BFS-DAG with no cross-edges and with each node having only one back-edge). The motivation for this is that it's much easier to work with trees then DAGs.
What's the problem with dealing with this BFS-Tree now? It's that some nodes that are reachable from
However, we observe that any node
Further, if some such
This leads to the following solution (I'm only giving a rough outline as I'm tired):
- Build an euler tour on an arbitrary BFS-Tree.
- For every node, compute the following six values:
- lowest in-time cross-edge
- lowest in-time back-edge
- lowest in-time forward-edge
- greatest in-time cross-edge
- greatest in-time back-edge
- greatest in-time forward-edge
- Build a merge sort tree on the euler tour such that for every node
, you store the aforementioned six things (in the form of pairs - , where is one of the six values and is dependent on the kind of edge being considered) at the leaf-node in the merge-sort tree at the in-time of . The rest of the merge-sort tree is built using the pairs at these leaf nodes. - To find the optimal
for some node , you simply need to perform a rectangle query over in this merge-sort tree to find a pair that (a) has first element outside (b) has the smallest possible value of the second element. There are a couple of edge cases though (for example, the back-edge might result in a false-positive), so deal with them in whatever manner you find convenient.
And oh, the case where the answer is
My code can be found here.