题意:给出n个点,n-1条边,保证每两个点之间的路径唯一,回答m个距离询问。
LCA离线算法 tarjan模板。
#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#define N 55000
using namespace std;
vector<int> h[N],w[N],q[N],num[N];
int ans[N],d[N],v[N],pre[N],n,m;
void init()
{
for(int i=1;i<=n;i++)
{
h[i].clear();
w[i].clear();
q[i].clear();
num[i].clear();
pre[i]=i;
d[i]=0;
v[i]=0;
}
}
int findset(int v)
{
while(v!=pre[v]) v=pre[v];
return v;
}
void unions(int u,int v)
{
int t1=findset(u);
int t2=findset(v);
if(t1!=t2) pre[t2]=t1;
}
void tarjan(int cur,int val)
{
v[cur]=1;
d[cur]=val;
int len=h[cur].size();
for(int i=0;i<len;i++)
{
int t=h[cur][i];
if(v[t]) continue;
tarjan(t,val+w[cur][i]);
unions(cur,t);
}
len=q[cur].size();
for(int i=0;i<len;i++)
{
int t=q[cur][i];
if(!v[t]) continue;
ans[num[cur][i]]=d[cur]+d[t]-2*d[findset(t)];
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>n>>m;
init();
for(int i=1;i<n;i++)
{
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
h[u].push_back(v);
w[u].push_back(c);
h[v].push_back(u);
w[v].push_back(c);
}
for(int i=0;i<m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
q[u].push_back(v);
q[v].push_back(u);
num[u].push_back(i);
num[v].push_back(i);
}
tarjan(1,0);
for(int i=0;i<m;i++) cout<<ans[i]<<endl;
}
}