Explanation

First, we need to divide queries into two types: those that require us to jump to the root, and those that don't require such. Let's consider a query for the shortest path uvu \rightarrow v.

Case 1: uu is an ancestor of vv

The optimal solution is for our path to just walk downwards from uu to vv. This is equivalent to dist(1v)dist(1u)\texttt{dist}(1 \rightarrow v) - \texttt{dist}(1 \rightarrow u), where 11 is the root of our tree. To answer these queries, we use the method described in this editorial.

Case 2: uu is not an ancestor of vv

In this scenario, our path from uu to vv has the following structure.

  1. First, we traverse down to some node in the subtree of uu
  2. Using the back edge at our chosen node, we jump to node 11.
  3. Finally, we walk down to node vv

We can use the same code for case 1 to calculate dist(1v)\texttt{dist}(1 \rightarrow v). However, it isn't exactly clear how we should figure out the best node to pick in the subtree of uu to jump from. Let the node we traverse down to be xx. Then, the cost of using node xx to jump to the root is:

dist(ux)+back[x]\texttt{dist}(u \rightarrow x) + \texttt{back}[x]

Here, back[x]\texttt{back}[x] refers to the cost of jumping from xx to the root. Using the same idea from case 1, we can change our expression a bit.

dist(1x)+back[x]dist(1u)\texttt{dist}(1 \rightarrow x) + \texttt{back}[x] - \texttt{dist}(1 \rightarrow u)

The distance from the root to node uu is fixed here. Thus, we want to find the best value of dist(1x)+back[x]\texttt{dist}(1 \rightarrow x) + \texttt{back}[x] within the subtree of uu. To do this, we use Euler Tour to flatten our tree, and then use a lazy segment tree to answer our queries.

Our segment tree must support range addition and range minimum. For more information on how to implement it, refer to the Range Updates Range Queries module.

Handling Updates

If the edge we are updating is from node uu to node 11, then it only affects the value in our segment tree for node uu. Thus, we do a point update on the node in question.

In the case that the edge we are updating isn't from some node to the root, then it changes all the values inside the subtree it affects. Let's have the edge affected connect node uu and node vv, with the difference in weight being ww. Then, we must do the following.

  • Change the distances in the subtree of vv by ww
  • Change the value of dist(1x)+back[x]\texttt{dist}(1 \rightarrow x) + \texttt{back}[x] by ww

In my code, this boils down to updating the binary indexed tree handling the root to node distances, and updating the segment tree containing the value of dist(1x)+back[x]\texttt{dist}(1 \rightarrow x) + \texttt{back}[x] for every node.

Implementation

Time Complexity: O((N+Q)logN)\mathcal{O}((N+Q)\log{N})

C++

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
Code Snippet: Lazy Segment Tree (from the module) (Click to expand)
Code Snippet: BIT (from the module) (Click to expand)
int main() {

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!