LOJ #10134. 「一本通 4.4 练习 1」Dis
做这道题需要知道一个性质:树上 \(x,y\) 两点的距离为 \(dis(x)+dis(y)-2dis(LCA(x,y))\),其中 \(dis(i)\) 表示 \(i\) 点离根节点的距离,\(LCA(i,j)\) 表示 \(i,j\) 两点的 LCA(最近公共祖先)。
然后就直接水过去了。在预处理 fa 数组时直接将 dis 数组带着预处理一遍就 A 掉了(这什么垃圾题解)。
Code:
#include <bits/stdc++.h>
using namespace std;
const int maxN=10005,logn=15;
struct Edge {int to,val,nxt;}edge[maxN<<1];
int n,m,tot,fa[maxN][logn],dep[maxN],hd[maxN],dis[maxN];
void add(int,int,int),dfs(int,int);
int LCA(int,int),query(int,int);
int main() {
scanf("%d%d",&n,&m);
for (int i=1;i<n;i++) {
int x,y,v;scanf("%d%d%d",&x,&y,&v);
add(x,y,v);
add(y,x,v);
}
dfs(1,1);
for (;m;m--) {
int x,y;scanf("%d%d",&x,&y);
printf("%d\n",query(x,y));
}
return 0;
}
void add(int x,int y,int v) {
edge[++tot].to=y;
edge[tot].val=v;
edge[tot].nxt=hd[x];
hd[x]=tot;
}
void dfs(int u,int d) {
dep[u]=d;
for (int i=hd[u];i;i=edge[i].nxt) {
int o=edge[i].to;
if (dep[o]) continue;
fa[o][0]=u;
for (int j=1;fa[o][j-1];j++)
fa[o][j]=fa[fa[o][j-1]][j-1];
dis[o]=dis[u]+edge[i].val;
dfs(o,d+1);
}
}
int LCA(int u,int v) {
if (dep[u]<dep[v]) swap(u,v);
for (int i=logn;~i;i--)
if (dep[u]-(1<<i)>=dep[v]) u=fa[u][i];
if (u==v) return u;
for (int i=logn-1;~i;i--)
if (fa[u][i]!=fa[v][i]) {
u=fa[u][i];
v=fa[v][i];
}
return fa[u][0];
}
int query(int u,int v) {return dis[u]+dis[v]-(dis[LCA(u,v)]<<1);}
转载是允许的,但是除了博主同意的情况下,必须在文章的明显区域说明出处,否则将会追究其法律责任。