大致题意:
一个城镇有n个房子,有n-1条双向路将n个房子连接起来,城镇中不会有环。每条路都有自己的长度,现在问你任意两个房子间的距离是多少。
既然不会形成环,那我们可以任选一点作为根,“吊挂”起来形成一棵树。那任意两个房子间的距离就是这两个房子的最近公共祖先分别到达两个房子距离的和。
我们先利用dfs将每个点到达根的距离都求出来,然后求A和B的距离就转换成(A和根部之间的距离 - 最近公共祖先和根部之间的距离)+(B和根部之间的距离 - 最近公共祖先和根部之间的距离)。
求最近公共祖先利用tarjian
代码:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<string.h>
#include<map>
using namespace std;
#define maxn 50000
int vis[maxn];
int go[maxn];
int to[maxn];
int fa[maxn];
int sum[maxn];
vector<int>V[maxn],C[maxn],cost[maxn];
map<pair<int,int>,int>M;
int find(int k)
{
int a=k,temp;
while(k!=fa[k])k=fa[k];
while(fa[a]!=k)
{
temp=fa[a];
fa[a]=k;
a=temp;
}
return k;
}
void dfs1(int su,int u,int e)
{
sum[u]=e;
for(int i=0; i<V[u].size(); i++)
{
if(V[u][i]==su)continue;
dfs1(u,V[u][i],e+cost[u][i]);
}
return;
}
void dfs2(int su,int u)
{
for(int i=0; i<V[u].size(); i++)
{
if(V[u][i]==su)continue;
dfs2(u,V[u][i]);
vis[V[u][i]]=1;
fa[V[u][i]]=u;
}
for(int i=0; i<C[u].size(); i++)
{
if(vis[C[u][i]])
{
M.insert(make_pair(make_pair(u,C[u][i]),sum[u]+sum[C[u][i]]-2*sum[find(C[u][i])]));
M.insert(make_pair(make_pair(C[u][i],u),sum[u]+sum[C[u][i]]-2*sum[find(C[u][i])]));
}
}
return;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
M.clear();
int n,m;
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
{
V[i].clear();
C[i].clear();
cost[i].clear();
vis[i]=0;
fa[i]=i;
}
int a,b,c;
for(int i=1; i<n; i++)
{
scanf("%d%d%d",&a,&b,&c);
V[a].push_back(b);
V[b].push_back(a);
cost[a].push_back(c);
cost[b].push_back(c);
}
dfs1(1,1,0);
for(int i=1; i<=m; i++)
{
scanf("%d%d",&go[i],&to[i]);
C[go[i]].push_back(to[i]);
C[to[i]].push_back(go[i]);
}
dfs2(1,1);
for(int i=1;i<=m;i++)
{
printf("%d\n",M[make_pair(go[i],to[i])]);
}
}
}