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;
}

posted @ 2025-05-05 11:04  Hootime  阅读(8)  评论(0)    收藏  举报