Let's think about ways we can embed a tree in a 2D plane such that paths can be covered by exactly two axis-aligned rectangles. One idea that comes to mind is that we might want to split a path into two parts and then use one box to cover one of those parts and another box to cover the other part.
Assume we arbitrarily root the input tree. A natural way to break a tree path into two parts is to break it into two parts such that both parts consist of a vertical chain in the tree (more formally, it contains a subset of the graph that forms one connected component and are all ancestors of one node in the subset). We can split any arbitrary path from $A$ to $B$ by having one path from $A$ to $LCA(A,B)$ (the lowest common ancestor of $A$ and $B$) and another path from $B$ to its ancestor that is one level below $LCA(A,B)$. (A special case is when $A=LCA(A,B)$ and thus the original path is already in the desired form.)
Now, we just need to find a way to embed a tree in a 2D plane such that vertical chains can be covered by one axis-aligned rectangle. Let's consider a recursive embedding. For each node $i$, we will deal with the subtree rooted at $i$. Let $S_i$ be the size of the subtree rooted at $i$. We will make an embedding of $i$'s subtree inside a $S_i \times S_i$ square such that for each node $j$ in $i$'s subtree, the rectangle with $j$ at the bottom-left corner and $i$ at the top-right corner contains exactly the nodes on the path from $i$ to $j$.
As a base-case, it's clear that a leaf node satisfies this constraint no matter how it is embedded (as long as we don't put any two nodes at the same point). Now, let's embed $i$ given that we know how to do an embedding for each of its children's respective subtrees. We will put $i$ at the top-right corner of our $S_i \times S_i$ square. Then, for some child $j$ we will take the $S_j \times S_j$ embedding for it and place it at the top-left corner of our $S_i \times S_i$ square. While $i$ has another child, we will take that child's square embedding and place it so that its top-left corner touches the bottom-right corner of the previous child's square embedding. Conveniently, this embedding of $i$'s subtree satisfies the desired constraints. Based on our embedding, the box with $i$ at the top-right corner and some descendant $j$ at the bottom-left corner will contain exactly the vertical chain from $i$ to $j$. This shows us a method of embedding the tree recursively. We can do this in $O(N)$ time.
Thus, we have $O(N)$ embedding of a tree into the plane. Then, for every query we want to break it into two vertical chains. We can do this as mentioned previously, by calculating LCA in $O(\log{N})$. Our final runtime is $O(N + Q \log{N})$.
#include "grader.h" using namespace std; int x[100000]; int y[100000]; vector<int> adj[100000]; int lc[18][100000]; int sub[100000]; int h[100000]; int dfs(int now, int from){ sub[now] = 1; lc[0][now] = from; if(from==-1){ h[now] = 0; } else{ h[now] = h[from]+1; } for(int i = 0; i<adj[now].size(); i++){ int to = adj[now][i]; if(to==from){ continue; } sub[now] += dfs(to,now); } return sub[now]; } void go(int now, int from, int ylo, int yhi, int xlo, int xhi){ x[now] = xlo; y[now] = ylo; setFarmLocation(now,xlo++,ylo++); for(int i = 0; i<adj[now].size(); i++){ int to = adj[now][i]; if(to==from){ continue; } go(to,now,ylo,ylo+sub[to]-1,xhi-sub[to]+1,xhi); ylo += sub[to]; xhi -= sub[to]; } } void addRoad(int a, int b){ adj[a].push_back(b); adj[b].push_back(a); } int lca(int a, int b){ if(h[a]<h[b]){ swap(a,b); } for(int i = 17; i>=0; i--){ int toa = lc[i][a]; if(toa!=-1 && h[toa]>=h[b]){ a = toa; } } if(a==b){ return a; } for(int i = 17; i>=0; i--){ int toa = lc[i][a]; int tob = lc[i][b]; if(toa!=tob){ a = toa; b = tob; } } return lc[0][a]; } void buildFarms(){ dfs(0,-1); int n = getN(); go(0,-1,1,n,1,n); for(int i = 1; i<18; i++){ for(int j = 0; j<n; j++){ if(lc[i-1][j]==-1){ lc[i][j] = -1; } else{ lc[i][j] = lc[i-1][lc[i-1][j]]; } } } } void notifyFJ(int a, int b){ int l = lca(a,b); addBox(x[l],y[l],x[a],y[a]); if(l==b){ return; } int ogb = b; for(int i = 17; i>=0; i--){ int tob = lc[i][b]; if(tob!=-1 && h[tob]>h[l]){ b = tob; } } addBox(x[b],y[b],x[ogb],y[ogb]); }