Processing math: 100%
(Analysis by Spencer Compton )

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 Si be the size of the subtree rooted at i. We will make an embedding of i's subtree inside a Si×Si 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 Si×Si square. Then, for some child j we will take the Sj×Sj embedding for it and place it at the top-left corner of our Si×Si 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(logN). Our final runtime is O(N+QlogN).

#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]);
}