#include #include #include #include #include // Use MAXN slightly larger than 200,000 for safety, e.g., 200005 const int MAXN = 200005; // log2(200000) is approx 17.6, so 18 levels are needed for binary lifting. const int LOGN = 18; std::vector adj[MAXN]; // Adjacency list for the tree int parent[MAXN]; // Stores the direct parent of each node in DFS traversal rooted at 1 int depth[MAXN]; // Stores the depth of each node (distance from root 1) int subtree_size[MAXN]; // Stores the size of the subtree rooted at each node in the DFS tree int up[MAXN][LOGN]; // Binary lifting table: up[u][i] is the 2^i-th ancestor of u /** * @brief Performs Depth First Search starting from node u to compute properties needed for LCA and subtree calculations. * * @param u Current node being visited. * @param p Parent of the current node in DFS traversal. * @param d Depth of the current node. */ void dfs(int u, int p, int d) { parent[u] = p; // Set parent depth[u] = d; // Set depth subtree_size[u] = 1; // Initialize subtree size with the node itself up[u][0] = p; // Base case for binary lifting: 2^0 = 1st ancestor is the parent // Precompute higher ancestors using binary lifting dynamic programming for (int i = 1; i < LOGN; ++i) { // The 2^i-th ancestor is the 2^(i-1)-th ancestor of the 2^(i-1)-th ancestor // Check if the (i-1)-th ancestor exists (is not 0, our dummy node above root) if (up[u][i-1] != 0) { up[u][i] = up[up[u][i-1]][i-1]; } else { // If ancestor at level 2^(i-1) doesn't exist, then ancestor at level 2^i also doesn't exist up[u][i] = 0; } } // Recurse for children for (int v : adj[u]) { if (v != p) { // Avoid going back up to the parent dfs(v, u, d + 1); subtree_size[u] += subtree_size[v]; // Update subtree size by adding sizes of children's subtrees } } } /** * @brief Finds the k-th ancestor of node u using binary lifting. * * @param u The node whose ancestor is to be found. * @param k The level of ancestor required (k=1 means parent, k=2 means grandparent etc.). * @return The k-th ancestor node ID, or 0 if the k-th ancestor is above the root. */ int get_ancestor(int u, int k) { // Check for invalid k or if u is already 0 (a possible state if previous jump went above root) if (k < 0 || u == 0) return 0; if (k == 0) return u; // 0-th ancestor is the node itself // Use binary lifting to jump up k levels efficiently for (int i = LOGN - 1; i >= 0; --i) { // If 2^i is less than or equal to the remaining distance k // This checks if the i-th bit of k is set if ((k >> i) & 1) { u = up[u][i]; // Jump up by 2^i levels // If we jumped above the root (reached node 0), stop if (u == 0) break; } } return u; // Return the k-th ancestor found } /** * @brief Finds the Lowest Common Ancestor (LCA) of nodes u and v. * * @param u First node. * @param v Second node. * @return The LCA node ID. */ int lca(int u, int v) { // Ensure u is the deeper node by swapping if necessary if (depth[u] < depth[v]) { std::swap(u, v); } // Bring u up to the same depth as v using get_ancestor u = get_ancestor(u, depth[u] - depth[v]); // If u and v are the same node now, they are the LCA if (u == v) { return u; } // Jump u and v up simultaneously using binary lifting // Find the highest ancestors of u and v that are different for (int i = LOGN - 1; i >= 0; --i) { if (up[u][i] != up[v][i]) { // If 2^i-th ancestors are different u = up[u][i]; // Jump u up v = up[v][i]; // Jump v up } } // After the loop, u and v are direct children of the LCA // The LCA is the parent of u (or v) return up[u][0]; } /** * @brief Calculates the distance (number of edges) between nodes u and v in the tree. * * @param u First node. * @param v Second node. * @return The distance between u and v. */ int dist(int u, int v) { int common_ancestor = lca(u, v); // Standard tree distance formula: dist(u,v) = depth(u) + depth(v) - 2*depth(lca(u,v)) return depth[u] + depth[v] - 2 * depth[common_ancestor]; } int main() { // Use fast I/O operations std::ios_base::sync_with_stdio(false); std::cin.tie(NULL); int N; // Number of vertices int Q; // Number of queries std::cin >> N >> Q; // Read edges and build adjacency list representation of the tree for (int i = 0; i < N - 1; ++i) { int u, v; std::cin >> u >> v; adj[u].push_back(v); adj[v].push_back(u); } // Precomputation step: Perform DFS starting from root 1 // This computes depths, parents, subtree sizes, and initializes binary lifting table dfs(1, 0, 0); // Assuming root is 1, its parent is 0 (dummy node), depth is 0 // Process each query for (int i = 0; i < Q; ++i) { int S, T; // Query vertices std::cin >> S >> T; // Calculate distance between S and T int d_ST = dist(S, T); // If distance is odd, no vertex can be equidistant. The answer is 0. if (d_ST % 2 != 0) { std::cout << 0 << "\n"; } else { // If distance is even, there is a unique midpoint vertex M on the path S-T. int k = d_ST / 2; // Half the distance int common_ancestor = lca(S, T); // Find LCA of S and T int d_S_L = depth[S] - depth[common_ancestor]; // Distance from S to LCA int M; // The midpoint vertex M // Determine the midpoint vertex M based on its position relative to S, T, and LCA if (d_S_L == k) { // Case 1: M is the LCA itself. This happens when S and T are equidistant from LCA. M = common_ancestor; } else if (d_S_L > k) { // Case 2: M is on the path from S to LCA (M is a proper ancestor of S). S is further than k from LCA. M = get_ancestor(S, k); // M is the k-th ancestor of S } else { // Case 3: M is on the path from LCA to T (M is a proper ancestor of T). S is closer than k to LCA. // Since d(S,M)=k and path is S->LCA->M, d(S,LCA)+d(LCA,M)=k. // Also d(T,M)=k. M is k-th ancestor of T. M = get_ancestor(T, k); // M is the k-th ancestor of T } // Find neighbors P_S and P_T of M on the unique path between S and T. // P_S is the neighbor towards S, P_T is the neighbor towards T. int P_S, P_T; // Determine P_S and P_T based on which case M falls into. if (M == common_ancestor) { // Case 1: M = LCA // Path: S... -> P_S -> M -> P_T -> ...T // P_S is the child of M towards S. P_T is the child of M towards T. // Since d(S, M)=k, P_S is (k-1)th ancestor of S. (k>=1 because S!=T) P_S = get_ancestor(S, k - 1); // Since d(T, M)=k, P_T is (k-1)th ancestor of T. P_T = get_ancestor(T, k - 1); } else if (lca(S, M) == M) { // Case 2: M is an ancestor of S (and M != LCA, since d_S_L > k). Path S -> M -> LCA -> T. // Path: S... -> P_S -> M -> P_T -> ...LCA -> ...T // P_S is child of M towards S. P_T is parent of M towards LCA. P_S = get_ancestor(S, k - 1); // P_S is (k-1)th ancestor of S P_T = parent[M]; // P_T is the parent of M based on DFS tree rooted at 1 } else { // Case 3: M is an ancestor of T (and M != LCA, since d_S_L < k). Path S -> LCA -> M -> T. // Path: S... -> LCA -> ... -> P_S -> M -> P_T -> ...T // P_S is parent of M towards LCA. P_T is child of M towards T. P_S = parent[M]; // P_S is the parent of M P_T = get_ancestor(T, k - 1); // P_T is (k-1)th ancestor of T } // Compute sizes of components/subtrees associated with P_S and P_T relative to M. // These represent the sets of vertices closer to S and T respectively. long long size_M_PS, size_M_PT; // Calculate size of the component containing P_S if edge (M, P_S) is removed. // This depends on whether M is parent of P_S or vice-versa in the DFS tree. if (P_S == 0) { // Edge case check, should not happen if S!=T, D>=2 size_M_PS = 0; } else if (parent[P_S] == M) { // If M is the parent of P_S in the rooted DFS tree size_M_PS = (long long)subtree_size[P_S]; // The size is simply the precomputed subtree size of P_S } else { // P_S must be the parent of M // The component containing P_S consists of all nodes *except* those in the subtree rooted at M. size_M_PS = (long long)N - subtree_size[M]; } // Calculate size of the component containing P_T if edge (M, P_T) is removed. if (P_T == 0) { // Edge case check size_M_PT = 0; } else if (parent[P_T] == M) { // If M is the parent of P_T size_M_PT = (long long)subtree_size[P_T]; // Size is the subtree size of P_T } else { // P_T must be the parent of M size_M_PT = (long long)N - subtree_size[M]; // Size is N minus the subtree size of M } // The number of vertices X such that d(X,S)=d(X,T) is the total number of vertices N // minus the sizes of the components "closer" to S (rooted at P_S relative to M) // and "closer" to T (rooted at P_T relative to M). long long total_nodes = N; long long answer = total_nodes - size_M_PS - size_M_PT; std::cout << answer << "\n"; } } return 0; }