標籤:
codevs 1036 商務旅行 時間限制: 1 s 空間限制: 128000 KB 題目等級 : 鑽石 Diamond題目描述
Description
某首都城市的商人要經常到各城鎮去做生意,他們按自己的路線去做,目的是為了更好的節約時間。
假設有N個城鎮,首都編號為1,商人從首都出發,其他各城鎮之間都有道路串連,任意兩個城鎮之間如果有直連道路,在他們之間行駛需要花費單位時間。該國公路網路發達,從首都出發能到達任意一個城鎮,並且公路網路不會存在環。
你的任務是協助該商人計算一下他的最短旅行時間。
輸入描述
Input Description
輸入檔案中的第一行有一個整數N,1<=n<=30 000,為城鎮的數目。下面N-1行,每行由兩個整數a 和b (1<=a, b<=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 #define N 60100 2 #include<iostream> 3 using namespace std; 4 #include<cstdio> 5 #include<cstring> 6 #define C 20 7 typedef long long ll; 8 int ance[N>>1][C],dis[N>>1],n,a,b,m; 9 ll sum=0;10 struct Edge{11 int v,last;12 }edge[N<<1];13 int deep[N>>1],head[N>>1],t=0;14 void add_edge(int u,int v)15 {16 ++t;17 edge[t].v=v;18 edge[t].last=head[u];19 head[u]=t;20 }21 void input()22 {23 scanf("%d",&n);24 for(int i=1;i<n;++i)25 {26 scanf("%d%d",&a,&b);27 add_edge(a,b);28 add_edge(b,a);/*注意樹上建邊必須是雙向的*/29 }30 }31 void dfs(int k)32 {33 for(int l=head[k];l;l=edge[l].last)34 {35 if(!deep[edge[l].v])36 {37 dis[edge[l].v]=dis[k]+1;38 ance[edge[l].v][0]=k;39 deep[edge[l].v]=deep[k]+1;40 dfs(edge[l].v);41 }42 }43 }44 void chuli_ance()45 {46 for(int i=1;(1<<i)<=n;++i)47 for(int j=1;j<=n;++j)48 ance[j][i]=ance[ance[j][i-1]][i-1];49 }50 int lca(int a,int b)51 {52 int i,j;53 if(deep[a]<deep[b]) swap(a,b);54 for(i=0;(1<<i)<=deep[a];++i);55 i--;56 for(j=i;j>=0;--j)57 if(deep[a]-(1<<j)>=deep[b])58 a=ance[a][j];59 if(a==b) return a;60 for(j=i;j>=0;--j)61 {62 if(ance[a][j]!=-1&&ance[a][j]!=ance[b][j])63 {64 a=ance[a][j];65 b=ance[b][j];66 }67 }68 return ance[a][0];69 }70 int main()71 {72 input();73 deep[1]=1;74 dis[1]=0;75 memset(ance,-1,sizeof(ance));76 dfs(1);77 chuli_ance();78 scanf("%d",&m);79 scanf("%d",&a);80 int sta=a;81 for(int i=2;i<=m;++i)82 {83 scanf("%d",&b);84 int zuxian=lca(a,b);85 sum+=(dis[a]+dis[b]-2*dis[zuxian]);86 a=b;87 }88 sum+=dis[sta];89 cout<<sum<<endl;90 return 0;91 }
倍增法-lca codevs 1036 商務旅行