题意:
给你n个点,m个询问,问你A,B之间最短的长度是多少。
题解:
这道题是一道求最近公共祖先的题,对于询问i,j的LCA,答案为dist[i]+dist[j]-2*dist[LCA(i,j)],这里dist[i]为i点到1号根节点的距离。 对于询问,要存放两次分别为(i,j),(j,i),因为LCA第一次问i,j的时候可能j还没被访问。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN=40000+7;
vector< pair<int,int> >map[MAXN];
vector< pair<int,int> >query[MAXN];
int fa[MAXN];
bool vis[MAXN];
int ans[MAXN];
int dis[MAXN];
int n,m,q;
void init()
{
for(int i=0;i<=n;i++)
{
map[i].clear();
query[i].clear();
fa[i]=i;
dis[i]=0;
vis[i]=false;
ans[i]=0;
}
}
int find(int p)
{
return fa[p]==p? p:fa[p]=find(fa[p]);
}
void Union(int p,int q)
{
int P=find(p);
int Q=find(q);
if(P!=Q)
{
fa[Q]=P;
}
}
void LCA_Tarjan(int u,int w)
{
vis[u]=true;
dis[u]=w;
for(int i=0;i<query[u].size();i++)
{
int v=query[u][i].first;
int j=query[u][i].second;
if(!vis[v]) continue;
ans[j]=dis[u]+dis[v]-2*dis[find(v)];
}
for(int i=0;i<map[u].size();i++)
{
int v=map[u][i].first;
if(vis[v]) continue;
LCA_Tarjan(v,w+map[u][i].second);
Union(u,v);
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
init();
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
map[u].push_back(make_pair(v,w));
map[v].push_back(make_pair(u,w));
}
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
query[u].push_back(make_pair(v,i));
query[v].push_back(make_pair(u,i));
}
// for(int i=1;i<=n;i++)
// for(int j=0;j<query[i].size();j++)
// printf("%d %d %d\n",i,query[i][j].first,query[i][j].second);
LCA_Tarjan(1,0);
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
}
}