hdu 2586 How far away ?(LCA)

Problem Description

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
解题思路:Tarjan算法求树上任意两点的最短路。
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const int maxn=40005;
 5 const int maxv=205;
 6 int T,n,m,x,y,z,fa[maxn],dist[maxn],ans[maxv];bool vis[maxn];
 7 vector<pair<int,int> > tree[maxn],query[maxn];
 8 void init(){
 9     for(int i=1;i<=n;++i)fa[i]=i,tree[i].clear(),query[i].clear();
10     memset(vis,false,sizeof(vis));
11     memset(dist,0,sizeof(dist));
12     memset(ans,0,sizeof(ans));
13 }
14 int query_father(int x){
15     int per=x,tmp;
16     while(fa[per]!=per)per=fa[per];
17     while(x!=per){tmp=fa[x];fa[x]=per;x=tmp;}//路径压缩
18     return x;
19 }
20 void unite(int x,int y){
21     x=query_father(x),y=query_father(y);
22     if(x!=y)fa[y]=x;
23 }
24 void Tarjan_LCA(int cur,int val){
25     vis[cur]=true;///先标记为true,这样如果同一支树上前面的祖先节点已访问,但是还没有归并到集合中去相当于为其本身,所以对下面计算两个节点的最近距离是没有影响的
26     dist[cur]=val;
27     for(size_t i=0;i<tree[cur].size();++i){
28         int v=tree[cur][i].first;
29         int w=tree[cur][i].second;
30         if(!vis[v]){
31             Tarjan_LCA(v,val+w);///先序遍历
32             unite(cur,v);///回退后续遍历归并集合
33         }
34     }
35     for(size_t i=0;i<query[cur].size();++i){///同时扫描与cur有关的点对查询
36         int to=query[cur][i].first;
37         int id=query[cur][i].second;
38         if(vis[to])ans[id]=dist[cur]+dist[to]-2*dist[query_father(to)];
39     }
40 }
41 int main(){
42     while(~scanf("%d",&T)){
43         while(T--){
44             scanf("%d%d",&n,&m);
45             init();
46             for(int i=1;i<n;++i){
47                 scanf("%d%d%d",&x,&y,&z);
48                 tree[x].push_back(make_pair(y,z));
49                 tree[y].push_back(make_pair(x,z));
50             }
51             for(int i=1;i<=m;++i){
52                 scanf("%d%d",&x,&y);
53                 query[x].push_back(make_pair(y,i));
54                 query[y].push_back(make_pair(x,i));
55             }
56             Tarjan_LCA(1,0);
57             for(int i=1;i<=m;++i)printf("%d
",ans[i]);
58         }
59     }
60     return 0;
61 }
原文地址:https://www.cnblogs.com/acgoto/p/10047053.html