Balkan OI 2012 - Shortest Paths

Author: Andi Qu

General graph -> Tree

General graphs are inconvenient - let's try to turn this graph into a tree!

Run Dijkstra's algorithm from node AA to every other node and construct the "shortest path tree" from this (i.e. the tree made of the union of the shortest paths from node AA to each other node). Make sure to force the lucky path given in the input to be in this tree!

Why is this useful? In this case, we get some cool properties from removing edges on the lucky path.

What happens when we remove an edge?

When we remove an edge on the lucky path, the tree splits into two smaller trees - one containing AA; one containing BB.

This means the shortest path ABA \rightarrow B must be of the form AuvBA \rightarrow u \rightarrow v \rightarrow B where uu and vv are two nodes joined by an edge and uu is in AA's tree while vv is in BB's tree.

Why is this true?

Firstly, any vertex is still connected to either AA via its shortest path tree or BB via its shortest path tree after a single edge on the shortest path is removed.

Secondly, we must "jump" from one subtree to the other at some point, so the new shortest paths must have two nodes in separate subtrees joined by an edge.

Updating the shortest paths

An important observation is that if you keep moving up from a node to its parent, you'll eventually reach a node on the lucky path. For node vv, let this node on the lucky path be PvP_v. Since NN is so small, we can just naively find PvP_v for each vv.

Since uu and vv must be in separate subtrees, the path AuvBA \rightarrow u \rightarrow v \rightarrow B is only a candidate for the shortest path after removing an edge if that edge lies between PuP_u and PvP_v.

We must thus only update the shortest paths after removing an edge for the edges between PuP_u and PvP_v for each edge (u,v)(u, v).

Again, we can just naively update these shortest paths.

The final complexity of this algorithm is O(MN+MlogN)\mathcal{O}(MN + M \log N)

Implementation

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
struct Edge {
int u, v;
ll c;
} edges[200000];
bool operator<(Edge a, Edge b) {

Join the USACO Forum!

Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!