Codevs 1036 商务旅行

 时间限制: 1 s   空间限制: 128000 KB   题目等级 : 钻石 Diamond
题目描述:

某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间。

假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇之间都有道路连接,任意两个城镇之间如果有直连道路,在他们之间行驶需要花费单位时间。该国公路网络发达,从首都出发能到达任意一个城镇,并且公路网络不会存在环。

你的任务是帮助该商人计算一下他的最短旅行时间。

输入描述 Input Description

输入文件中的第一行有一个整数N,1<=n<=30 000,为城镇的数目。下面N-1行,每行由两个整数a 和b (1<=ab<=n; a<>b)组成,表示城镇a和城镇b有公路连接。在第N+1行为一个整数M,下面的M行,每行有该商人需要顺次经过的各城镇编号。

输出描述 Output Description

    在输出文件中输出该商人旅行的最短时间。

样例输入 Sample Input
5
1 2
1 5
3 5
4 5
4
1
3
2
5
样例输出 Sample Output

7

 1 #include<cstring>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<iostream>
 5 using namespace std;
 6 #define maxn 30010
 7 #define S 16
 8 int n,m,a[30010],deep[30010],fa[maxn][S+10],ans,p1,p2,head[30010],num;
 9 
10 struct node{
11     int u,v,pre;
12 }e[maxn*2];
13 void dfs(int now,int from,int deepth)
14 {
15     fa[now][0]=from;
16     deep[now]=deepth;
17     for(int i=head[now];i;i=e[i].pre)
18       if(e[i].v!=from)
19         dfs(e[i].v,now,deepth+1);
20 }
21 void get_fa()
22 {
23     for(int j=1;j<=S;j++)
24         for(int i=1;i<=n;i++)
25             fa[i][j]=fa[fa[i][j-1]][j-1];
26 }
27 int LCA(int a,int b)
28 {
29     if(deep[a]<deep[b])swap(a,b); 
30     for(int j=S;j>=0;j--)
31       if((deep[a]-(1<<j))>=deep[b])
32         a=fa[a][j];
33     if(a==b)return a;
34     for(int i=S;i>=0;i--)
35       if(fa[a][i]!=fa[b][i])
36         {
37           a=fa[a][i];
38           b=fa[b][i];
39         }
40     return fa[a][0];
41 }
42 void add_egre(int from,int to)
43 {
44     num++;
45     e[num].u=from;
46     e[num].v=to;
47     e[num].pre=head[from];
48     head[from]=num;
49 }
50 int main()
51 {
52     scanf("%d",&n);
53     for(int i=1,x,y;i<n;i++)
54     {
55         scanf("%d%d",&x,&y);
56         add_egre(x,y);add_egre(y,x);
57     }
58     scanf("%d%d",&m,&p1);
59     memset(deep,0,sizeof(deep));
60     dfs(1,1,0);
61     get_fa();
62     for(int i=1;i<=m-1;i++)
63     {
64         scanf("%d",&p2);
65         int k=LCA(p1,p2);
66         ans+=deep[p1]+deep[p2]-2*deep[k];// deep 该点的深度
67         p1=p2;
68     }
69     printf("%d
",ans);
70     return 0;
71 }

思路:树上任意两点间的最短距离等于deep[p1]+deep[p2]-2*deep[p1,p2的最近公共祖先]

原文地址:https://www.cnblogs.com/suishiguang/p/6103601.html