商务旅行

Description

  某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间。
  假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇之间都有道路连接,任意两个城镇之间如果有直连道路,在他们之间行驶需要花费单位时间。该国公路网络发达,从首都出发能到达任意一个城镇,并且公路网络不会存在环。
  你的任务是帮助该商人计算一下他的最短旅行时间。

Input

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

Output

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

Sample Input

5
1 2
1 5
3 5
4 5
4
1
3
2
5
Sample Output

7

题解

lca的模板题,先跑一次记录没给点的深度,(s,t)的最短距离是d[s]+d[t]-2*d[fa(s,t)]
~~o(>_<)o ~~,第一次做,多打几遍就会了。

代码

type
  ab=^node;
    node=record
    a,b:longint;
    c:ab;
end;
var
  n,m,tot,sum:longint;
  p:array[0..30000]of ab;
  v:array[0..30000]of boolean;
  f,f1:array[0..30000,0..200]of longint;
  d:array[0..30000]of longint;
procedure put(x,y:longint);
var
  i:ab;
begin
  new(i);
  i^.a:=y;
  i^.c:=p[x];
  p[x]:=i;
end;
procedure fq(x,y,z:longint);
var
  i,j:longint;
begin
  f[y,0]:=x;
  f1[y,0]:=z;
  i:=x; j:=1;
  while f[i,j-1]>0 do
    begin
      f[y,j]:=f[i,j-1];
      f1[y,j]:=f1[y,j-1]+f1[i,j-1];
      i:=f[i,j-1];
      inc(j);
    end;
end;
procedure find(x,y:longint);
var
  i:ab;
begin
  v[x]:=true;
  d[x]:=y;
  i:=p[x];
  while i<>nil do
    begin
      if v[i^.a]=false then
        begin
          fq(x,i^.a,1);
          find(i^.a,y+1);
        end;
      i:=i^.c;
    end;
end;
function fa(x,y:longint):longint;
var
  i,j:longint;
begin
  if d[x]<d[y] then
    begin
      i:=x;x:=y;y:=i;
    end;
  i:=d[x]-d[y];
  j:=0;
  while i>0 do
    begin
      if i mod 2=1 then
        begin
          sum:=f1[x,j]+sum;
          x:=f[x,j];
        end;
       i:=i div 2;
       j:=j+1;
    end;
  if x=y then exit(sum);
  j:=0;
  while f[x,0]<>f[y,0] do
    begin
       while f[x,j]=f[y,j] do dec(j);
       sum:=sum+f1[x,j];
       x:=f[x,j];
       sum:=sum+f1[y,j];
       y:=f[y,j];
       j:=j+1;
    end;
  sum:=sum+f1[x,0];
  sum:=sum+f1[y,0];
  exit(sum);
end;
var
  i,s,t:longint;
begin
  readln(n);
  for i:=1 to n-1 do
    begin
     readln(s,t);
     put(s,t);
     put(t,s);
    end;
  find(1,1);
  readln(m);
  readln(s);
  for i:=2 to m do
    begin
      sum:=0;
      readln(t);
      tot:=tot+fa(s,t);
      s:=t;
    end;
  writeln(tot);
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值