商务旅行(codevs 1036)
题目描述 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
/* 倍增 LCA */ #include<cstdio> #include<iostream> #include<vector> #define M 30010 #define S 20 using namespace std; int deep[M],fa[M][S+5],n,m; vector<int> grap[M]; void dfs(int now,int from,int c) { fa[now][0]=from; deep[now]=c; for(int i=0;i<grap[now].size();i++) if(from!=grap[now][i]) dfs(grap[now][i],now,c+1); } void get_fa() { for(int j=1;j<=S;j++) for(int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; } int get_same(int a,int t) { for(int i=0;i<=S;i++) if(t&(1<<i)) a=fa[a][i]; return a; } int LCA(int a,int b) { if(deep[a]<deep[b])swap(a,b); a=get_same(a,deep[a]-deep[b]); if(a==b)return a; for(int i=S;i>=0;i--) if(fa[a][i]!=fa[b][i]) { a=fa[a][i]; b=fa[b][i]; } return fa[a][0]; } int main() { scanf("%d",&n); for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); grap[x].push_back(y); grap[y].push_back(x); } dfs(1,1,0); get_fa(); int p1,p2,ans=0; scanf("%d%d",&m,&p1); for(int i=1;i<m;i++) { scanf("%d",&p2); int zu=LCA(p1,p2); ans+=(deep[p1]+deep[p2]-2*deep[zu]); p1=p2; } printf("%d",ans); return 0; }