http://acm.hdu.edu.cn/showproblem.php?pid=2586
How far away ?
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 21250 Accepted Submission(s): 8368
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.
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
题目大意:给一个有权树,有Q次询问,求任意两点的距离。
题目分析:在树中有一个性质:任意两点的距离 ANS = dist[ u ] + dist[ v ] - dist[ lca(u,v) ],其中dist[ I ]是根到 I 的 距离 ,由于需要多次询问,所以使用Tarjan离线求LCA比较快
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 #include<vector> 6 using namespace std; 7 const int maxn=40005; 8 struct edge{ 9 int to; 10 int len; 11 }; 12 vector<struct edge>G[maxn]; 13 vector<int>qury[maxn]; 14 vector<int>num[maxn]; 15 int dis[maxn],vis[maxn],ans[maxn],fa[maxn]; 16 void init() 17 { 18 memset(dis,0,sizeof(dis)); 19 memset(vis,0,sizeof(vis)); 20 for(int i = 0 ; i < 40005 ; i++) 21 { 22 G[i].clear(); 23 qury[i].clear(); 24 num[i].clear(); 25 fa[i]=i; 26 } 27 } 28 int find(int x) 29 { 30 int xx=x; 31 while(fa[x]!=x) 32 { 33 x=fa[x]; 34 } 35 while(fa[xx]!=x) 36 { 37 int t=fa[xx]; 38 fa[xx]=x; 39 xx=t; 40 } 41 return x; 42 } 43 void Union(int x,int y) 44 { 45 int xx=find(x); 46 int yy=find(y); 47 if(xx!=yy); 48 fa[yy]=xx;//在完成子节点的Tarjan遍历之后,把子节点纳入父节点名下 49 } 50 void Tarjan(int u,int ll) 51 { 52 vis[u]=1; 53 dis[u]=ll; 54 for(int i = 0 ; i< G[u].size() ;i++) 55 { 56 struct edge wqw=G[u][i]; 57 if(vis[wqw.to])continue; 58 Tarjan(wqw.to,wqw.len+ll); 59 Union(u,wqw.to); 60 } 61 for(int i = 0 ; i < qury[u].size() ; i++) 62 { 63 if(vis[qury[u][i]]) 64 { 65 ans[num[u][i]]=dis[u]+dis[qury[u][i]]-2*dis[find(qury[u][i])]; 66 } 67 } 68 } 69 int main() 70 { 71 int t; 72 scanf("%d",&t); 73 while(t--) 74 { 75 init(); 76 int n,m; 77 scanf("%d%d",&n,&m); 78 for(int i = 1 ; i < n ; i++) 79 { 80 int a,b,c; 81 scanf("%d%d%d",&a,&b,&c); 82 G[a].push_back((struct edge){b,c}); 83 G[b].push_back((struct edge){a,c}); 84 } 85 for(int i = 0 ; i < m ; i++) 86 { 87 int a,b; 88 scanf("%d%d",&a,&b); 89 qury[a].push_back(b); 90 qury[b].push_back(a); 91 num[a].push_back(i); 92 num[b].push_back(i); 93 } 94 Tarjan(1,0); 95 for(int i = 0 ; i < m ; i++) 96 { 97 printf("%d\n",ans[i]); 98 } 99 } 100 return 0; 101 }