【HDU 2586 How far away ?】 邻接表+dfs+LCA(最近公共祖先问题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586

题目大意:有一棵n个节点n-1条边的树。然后给你两个点u,v,让你求u到v的距离。

解题思路:

     m询问次数比较小,算一下时间复杂度。用邻接表+bfs完全可以过。

     会的就不写了,这里我用邻接表+dfs+LCA。做的最近公共祖先第一题。可做模板。 感谢袁神!!!

   

 1 #pragma comment(linker, "/STACK:1024000000,1024000000")  /// hdu可以用这个操作防止栈溢出,强大~
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cmath>
 5 #include <vector>
 6 #include <algorithm>
 7 #include <cstring>
 8 using namespace std;
 9 
10 const int maxn=40005;
11 int n;
12 struct Node{   
13     int v, w;
14     Node(int v_, int w_){
15         v= v_, w= w_;
16     }
17 };
18 vector<Node>vt[maxn];  ///  用数组的话肯定存不下的,所以用vector
19 
20 int dep[maxn];    ///      记录每个节点离根节点的深度
21 int father[maxn];  ///     记录上一节点
22 int dis[maxn];     ///     记录离根节点的距离
23 
24 void dfs(int u, int fa, int deep){
25     father[u]= fa;
26     dep[u]= deep;
27     for(int i=0; i<vt[u].size(); ++i){ 
28         int v= vt[u][i].v;
29         if( v==fa ) continue; ///特判一下与父节点相连的边,防止进入死循环
30         dis[v]= dis[u]+vt[u][i].w;
31         dfs( v, u, deep+1 );
32     }
33 }
34 
35 int p[maxn][30];
36 
37 void Init_LCA(){       ///因为自己的父节点已经dfs找出来了,所以进行打表
38     for(int j=0; (1<<j)<=n; ++j)
39         for(int i=1; i<=n; ++i)
40             p[i][j]= -1;
41     for(int i=1; i<=n; ++i) p[i][0]= father[i];
42     for(int j=1; (1<<j)<=n; ++j)   ///以2的指数形式进行操作
43         for(int i=1; i<=n; ++i)
44             if( p[i][j-1] != -1 )
45                 p[i][j]= p[ p[i][j-1] ][ j-1 ];  ///这一步最关键了 
46 }
47 
48 int LCA(int x, int y){
49     if( dep[x] < dep[y] ) swap( x, y );
50     int i, lg;
51     for(lg=0; (1<<lg)<=dep[x]; ++lg);
52     --lg;
53     for(i=lg; i>=0; --i) /// 达到同一水平线上(也就是同一rank值);
54         if( dep[x] - (1<<i) >= dep[y] )
55             x= p[x][i];
56     if( x==y ) return x;
57     /// x,y在同一水平线上,使x,y以相同的步进速度往上走,直到达到LCA处;
58     for(i=lg; i>=0 ;--i)
59         if( p[x][i]!=-1 && p[x][i]!=p[y][i] )
60             x= p[x][i], y= p[y][i];
61     return father[x];
62 }
63 
64 int main()
65 {
66     int m, T, u, v, c;
67     cin >> T;
68     while(T--)
69     {
70         for(int i=0; i<=n; i++)
71             vt[i].clear();
72         cin>>n>>m;
73         for(int i=1; i<n; ++i){
74             int x, y, w;
75             scanf("%d%d%d", &x,&y,&w);
76             vt[x].push_back( Node( y, w ) );  ///直接存入Node,这样就把点和边一起存进去了
77             vt[y].push_back( Node( x, w ) );
78         }
79 
80         dis[1]= 0;
81         dfs(1, -1, 0);
82         Init_LCA();
83         while(m--){
84             int x, y;
85             scanf("%d%d", &x, &y);
86             printf("%d\n", dis[x] + dis[y] - 2*dis[ LCA(x, y) ]);  ///x到y的距离为x到根节点的距离加上y到根节点的距离减去两倍的最近公共祖先节点到根节点的距离
87         }
88     }
89 }
原文地址:https://www.cnblogs.com/kane0526/p/2800625.html