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
資料範圍及提示 Data Size & Hint
沒有環QAQ
整張圖n個點 n-1條邊
所以這是棵樹
一棵樹上的兩個點會是什麼關係。
看下圖↓
第一種 點2和點4,點3和點7這種 在同一條鏈上的
第二種 點4和點5,點5和點6這種 隔了十萬八千裡的
對於第一種直接走過去就好啦
對於第二種 查詢公用祖先~
用點4和點5舉個例子
就是 4的深度 + 5的深度 - 2 * 2的深度
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int MAXN = 70005;int n,m,qq,tot = 0;int f,t,x,ans = 0,now = 1;int first[MAXN],next[MAXN];int fa[MAXN][35],deep[MAXN];struct edge{ int f,t;}l[MAXN];void init(){ memset(first,0xff,sizeof(first)); tot = 0; return;}void build(int f,int t){ l[++ tot] = (edge){f,t}; next[tot] = first[f]; first[f] = tot; return;}void dfs(int x,int f){ fa[x][0] = f; deep[x] = deep[f] + 1; for(int i = first[x]; i != -1; i = next[i]) if(l[i].t != f) dfs(l[i].t,x); return;}void make_fa(){ for(int j = 1; j <= 20; j ++) for(int i = 1; i <= n; i ++) fa[i][j] = fa[fa[i][j - 1]][j - 1]; return;}int lca(int x,int y){ if(deep[x] < deep[y]) swap(x,y); for(int j = 20; j >= 0; j --) if(deep[fa[x][j]] >= deep[y]) x = fa[x][j]; if(x == y) return x; for(int j = 20; j >= 0;j --) if(fa[x][j] != fa[y][j]) x = fa[x][j],y = fa[y][j]; return fa[x][0];}int ask(int x,int y){ return deep[x] + deep[y] - (deep[lca(x,y)] << 1);}int main(){ init(); scanf("%d",&n); for(int i = 1; i < n; i ++) { scanf("%d %d",&f,&t); build(f,t),build(t,f); } deep[0] = -1; dfs(1,0); make_fa(); scanf("%d",&qq); while(qq --) { scanf("%d",&x); ans += ask(now,x); now = x; } printf("%d\n",ans); return 0;}