Solution - P8805 [蓝桥杯 2022 国 B] 机房
A problem made of H\(_{\tiny\text{2}}\)O.
思路
一道简单的 LCA + 树上前缀和。
求出 LCA,然后用前缀和干出 LCA 到两点路径长度就行了。(树上路径长度不都这么做吗)
代码
#include <bits/stdc++.h>
#define rint register int
#define rllong register long long
#define llong long long
#define N 100005
using namespace std;
int to[N<<1], nxt[N<<1], head[N], gsiz;
#define mkarc(u,v) (++gsiz,to[gsiz]=v,nxt[gsiz]=head[u],head[u]=gsiz)
int pre[N], dep[N] = {0, 1}, fa[N][25];
int n, q;
inline void dfs(rint u){
for(rint i = 1; i < 25; ++i)
fa[u][i] = fa[fa[u][i-1]][i-1];
for(rint i = head[u]; i; i = nxt[i]){
rint v = to[i];
if(v == fa[u][0]) continue;
fa[v][0] = u, pre[v] += pre[u], dep[v] = dep[u]+1;
dfs(v);
}
return;
}
inline int lca(rint u, rint v){
if(dep[u] > dep[v]) swap(u, v);
for(rint i = 24; i >= 0; --i)
if(dep[v]-(1<<i) >= dep[u]) v = fa[v][i];
if(u == v) return u;
for(rint i = 24; i >= 0; --i)
if(fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
return fa[u][0];
}
int main(){
scanf("%d %d", &n, &q);
for(rint i = 1; i < n; ++i){
rint u, v;
scanf("%d %d", &u, &v);
mkarc(u, v), mkarc(v, u);
++pre[u], ++pre[v];
}
dfs(1);
while(q--){
rint u, v, k;
scanf("%d %d", &u, &v);
k = lca(u, v);
// cerr<<"[Debug] "<<u<<" "<<v<<" "<<k<<" "<<fa[k][0]<<endl;
printf("%d\n", pre[u]+pre[v]-pre[k]-pre[fa[k][0]]);
}
return 0;
}