There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house B"? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path("simple" means you can't visit a place twice) between every two houses. Yout task is to answer all these curious people.
Input
First line is a single integer T(T<=10), indicating the number of test cases.
For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
Output
For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.
Sample Input
2
3 2
1 2 10
3 1 15
1 2
2 3
2 2
1 2 100
1 2
2 1
Sample Output
10
25
100
100
题解:
首先要知道:树上任意两点A,B之间的距离 = 根节点到A的距离 + 根节点到B的距离 - 2*根节点到AB最近公共祖先节点的距离。
然后只要求LCA就行了。
Tarjan离线版代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 40005;
pair<int,int> P[205];//存询问边
int lca[205];//存询问边对应的最近公共祖先
struct Edge{//存树边
int to,next,w;//w为边权
}E[MAXN*2];
int head[MAXN],tot;
inline void Add(int from,int to,int w){
E[++tot].next = head[from];
E[tot].to = to;
E[tot].w = w;
head[from] = tot;
E[++tot].next = head[to];
E[tot].to = from;
E[tot].w = w;
head[to] = tot;
}
struct Query{//存每个点对应的询问边
int to,next,id;
}Q[405];
int headQ[MAXN],totq;
inline void AddQ(int from,int to,int id){
Q[++totq].next = headQ[from];
Q[totq].to = to;
Q[totq].id = id;
headQ[from] = totq;
Q[++totq].next = headQ[to];
Q[totq].to = from;
Q[totq].id = id;
headQ[to] = totq;
}
int dis[MAXN];//记录根节点到每个点的距离
bool vis[MAXN];
int fa[MAXN];//并查集祖先数组
int Find(int x){
if(fa[x] == x)return x;
return fa[x] = Find(fa[x]);
}
void Union(int a,int b){
int A = Find(a);
int B = Find(b);
if(A != B)fa[B] = A;
}
void Tarjan(int rt){
vis[rt] = true;
int to;
for(int i=head[rt] ; i ; i=E[i].next){
to = E[i].to;
if(!vis[to]){
dis[to] = dis[rt] + E[i].w;
Tarjan(to);
Union(rt,to);
}
}
for(int i=headQ[rt] ; i ; i=Q[i].next){
to = Q[i].to;
if(vis[to]){
lca[Q[i].id] = Find(to);
}
}
}
inline void init(int n){
for(int i=0 ; i<=n ; ++i)fa[i] = i;
memset(vis,false,sizeof vis);
memset(head,0,sizeof head);
memset(headQ,0,sizeof headQ);
tot = totq = 0;
}
int main(){
int T,n,m;
scanf("%d",&T);
while(T--){
scanf("%d %d",&n,&m);
init(n);
int a,b,c;
for(int i=1 ; i<n ; ++i){
scanf("%d %d %d",&a,&b,&c);
Add(a,b,c);
}
for(int i=1 ; i<=m ; ++i){
scanf("%d %d",&P[i].first,&P[i].second);
AddQ(P[i].first,P[i].second,i);
}
dis[1] = 0;//这里选的根节点为 1
Tarjan(1);
for(int i=1 ; i<=m ; ++i){
printf("%d\n",dis[P[i].first]+dis[P[i].second]-2*dis[lca[i]]);
}
}
return 0;
}