Explanation
Let , , and be the nodes given in each query, and be the LCA of and . Directly updating the path from to is difficult to do, so breaking up the path into smaller segments is necessary. To do that, we use some casework.
Case 1: is equal to , or is not inside 's subtree.
In this case, we update the path from to and to . Note that if is equal to either or , then this case must be handled slightly differently.
Case 2: is equal to either or .
Let the first ancestor of that is on the path from to be . WLOG, let be equal to . Then, we update the path from to and the path from to .
Case 3: The LCA of with and is the same as .
Like how we handled case 1, for this case we update the path from to and the path from to .
Case 4: Either the LCA of and or the LCA of and lie on the path from to .
In this case, split the path updates into 3 segments. Let the lower of the two LCAs mentioned be , and the node which is an ancestor of be . Then, just update the path from to , to , and the path from to .
Handling Path Updates
Note that based on how we did our casework on the paths, that all path updates are between a given node and its ancestor. Also, note that the path updates are just adding distances which either increase or decrease by a fixed amount every time. So, we can sort of do a difference array on a tree, where we DFS down the tree and apply the differences while walking back up the tree.
Implementation
Time Complexity:
C++
#include <bits/stdc++.h>using namespace std;using ll = long long;class Tree {private:const int n;const int log2dist; // # of bits needed for binary liftvector<vector<int>> &adj; // reference to adjacency listvector<vector<int>> lift; // for binary lifting
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!