CSES - Planets Queries II

Authors: Michael Cao, Benjamin Qi

In this problem, we are given a directed graph and asked qq queries for the minimum distance between two vertices uu and vv.

Main Idea

The graph is a functional graph, so break it into tree / cycle cases and solve each one independently.

Structure of the Graph

While the graph given in the statement can be modeled as a directed graph, we can be more specific. Since each vertex has one outgoing edge, the resulting graph is a Functional Graph.

An important property of a functional graph is that it's structure is composed of many trees directed towards the root, and a single cycle composed of the roots. So, we can break the graph into two cases.

Tree Case

The first case is if uu and vv are on the same tree. To check this, we can store the root of the tree that each vertex is on in functional graph, and check if the roots for uu and vv are equal.

If they are, the problem reduces to finding the distance between two vertices on a tree, which equals depthu+depthv2depthlca(u,v)depth_u + depth_v - 2 \cdot depth_{lca(u, v)} where lca(a,b)lca(a, b) denotes the lowest common ancestor of vertices aa and bb and depthxdepth_x denotes the distance from the vertex to the root of its tree. If you don't know how to compute lcalca, read Binary Jumping.

Cycle Case

Technically, there are 3 more cases, but they can be solved in the same way so we will group them together. The cycle case is when you need to cross the cycle to go from one vertex to another.

The three situations where this occurs are:

  • One vertex is on a tree, and the other is on the cycle.
  • Both vertices are on the cycle.
  • Both vertices are on trees, but they have different roots.

In all 3 cases, the distance can be computed the same way as depthu+depthv+distru,rvdepth_u + depth_v + dist_{r_u, r_v} where rxr_x denotes the root of the tree xx is on. Note that if a node is on a cycle, it is the root of its tree. To compute the distance between roots, we can give an arbitrary vertex value 00 and increase the value as you go around the cycle, similar to how you compute its length in the Functional Graph article.

Then, the distance between two roots is min(len(valuvalv),valuvalv)min(len - (val_u - val_v), val_u - val_v) where lenlen is the length of the cycle and valu>valvval_u > val_v, representing going from uu to vv in either direction.

C++

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using db = double;
using str = string; // yay python!
using pi = pair<int,int>;
using pl = pair<ll,ll>;

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!