题目描述 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……,lca模板题,虽然看数据需要倍增下,其实暴力lca也能过= =,代码打得比较随意233。
代码如下
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int sz = 200010;
int head[sz],nxt[sz],dis[sz][22],par[sz][22],deep[sz],tot = 1,n,m,num[sz],l[sz];
int read()
{
int x = 0 , f = 1;
char in = getchar();
while(in < '0' || in > '9')
{
if(in == '-')
f = -1;
in = getchar();
}
while('0' <= in && in <= '9')
{
x = (x << 3) + (x << 1) + in - '0';
in = getchar();
}
return x * f;
}
void build_edge(int f,int t)
{
l[tot] = t;
nxt[tot] = head[f];
head[f] = tot ++;
}
void dfs(int u,int fa,int dep)
{
dis[u][0] = 1;
par[u][0] = fa;
deep[u] = dep;
for(int i = head[u] ; i ; i = nxt[i])
if(l[i] != fa)
dfs(l[i],u,dep+1);
}
int lca(int u,int v)
{
int ans = 0;
if(deep[u] < deep[v])
swap(u,v);
for(int i = 21 ; i >= 0 ; i --)
if(deep[par[u][i]] >= deep[v])
ans += dis[u][i] , u = par[u][i];
for(int i = 21 ; i >= 0 ; i --)
if(par[u][i] != par[v][i])
ans += dis[u][i] + dis[v][i] , u = par[u][i] , v = par[v][i];
if(u != v)
ans += 2;
return ans;
}
void start_work()
{
n = read();
for(int i = 1 ; i < n ; i ++)
{
int u = read() , v = read();
build_edge(u,v);
build_edge(v,u);
}
m = read();
for(int i = 1 ; i <= m ; i ++)
num[i] = read();
dfs(1,0,1);
for(int j = 1 ; j <= 21 ; j ++)
for(int i = 1 ; i <= n ; i ++)
par[i][j] = par[par[i][j-1]][j-1],
dis[i][j] = dis[i][j-1] + dis[par[i][j-1]][j-1];
}
void nidaoshidonga_jpg()
{
int ans = 0;
for(int i = 2 ; i <= m ; i ++)
ans += lca(num[i],num[i-1]);
printf("%d\n",ans);
}
int main()
{
start_work();
nidaoshidonga_jpg();
return 0;
}