JZOI5257. 小X的佛光
题目花里胡哨扯一堆,其实就是让我们求两条路径的重合点数。
那么,直接求LCA然后计算即可。
对于路径 AC, CB, 其重叠路径即为 $(dis[(a、b -> LCA(A, B)] + dis[b、c -> LCA(B, C)] - dis[a、c -> LCA(A, C)]) / 2 + 1$ -> 除以$2$是因为重复计算了路径。加$1$是因为末端点B也算
#include <bits/stdc++.h> using namespace std; #define N 1000010 inline int read(){ int x = 0, s = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-')s = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); } return x * s; } struct node{ int v, next; } t[N << 1]; int f[N]; int bian = 0; inline void add(int u, int v){ t[++bian] = (node){v, f[u]}, f[u] = bian; t[++bian] = (node){u, f[v]}, f[v] = bian; return ; } int deth[N], siz[N], son[N], fa[N], top[N]; #define v t[i].v void dfs1(int now, int father){ siz[now] = 1; fa[now] = father; deth[now] = deth[father] + 1; for(int i = f[now]; i; i = t[i].next){ if(v != father){ dfs1(v, now); siz[now] += siz[v]; if(siz[v] > siz[son[now]]) son[now] = v; } } return ; } void dfs2(int now, int tp){ top[now] = tp; if(!son[now]) return ; dfs2(son[now], tp); for(int i = f[now]; i; i = t[i].next){ if(v != fa[now] && v != son[now]) dfs2(v, v); } return ; } int lca(int x, int y){ while(top[x] != top[y]){ if(deth[top[x]] < deth[top[y]]) swap(x, y); x = fa[top[x]]; } return deth[x] > deth[y] ? y : x; } #undef v int main(){ // freopen("hh.txt", "r", stdin); // freopen("5.txt", "w", stdout); int n = read(), T = read(), num = read(); for(int i = 1;i < n; i++){ int x = read(), y = read(); add(x, y); } if(num != 17 && num != 18){ dfs1(1, 1); dfs2(1, 1); while(T--){ int a = read(), b = read(), c = read(); int ans1 = abs(2 * deth[lca(a, b)] - deth[b] - deth[a]); int ans2 = abs(2 * deth[lca(a, c)] - deth[a] - deth[c]); int ans3 = abs(2 * deth[lca(b, c)] - deth[b] - deth[c]); printf("%d\n", (ans1 + ans3 - ans2) / 2 + 1); } } else { while(T--){ int a = read(), b = read(), c = read(); if((a < b && c > b) || (c < b && a > b)) puts("1"); else { printf("%d\n", min(abs(b - a), abs(c - b)) + 1) ; } } } return 0; }