CodeVS 2370-小机房的树

原题

题目描述 Description

小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力.已知从某个节点爬到其父亲节点要花费c的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要你设计一个程序来找到这条路,要求你告诉他们最少需要花费多少精力.//题面有点恶心,但题还是挺不错的233

输入描述 Input Description

第一行一个n,接下来n-1行每一行有三个整数u,v,c.表示节点 u 爬到节点 v 需要花费 c 的精力.
第n+1行有一个整数m表示有m次询问.接下来m行每一行有两个整数u,v表示两只虫子所在的节点.

输出描述 Output Description

一共有m行,每一行一个整数,表示对于该次询问所得出的最短距离.

样例输入 Sample Input

3

1 0 1

2 0 1

3

1 0

2 0

1 2

样例输出 Sample Output

1

1

2

 

数据范围及提示 Data Size & Hint

1<=n<=50000, 1<=m<=75000, 0<=c<=1000

 

题解

LCA,最近公共祖先.

用一个p数组储存节点i到根节点的距离.假设要求节点x与y之间的距离,则ans=p[x]+p[y]-2*p[lca(x,y)].

代码:

 

var p,f,ne,c,b,d:array[0..200010] of longint;
var fa:array[0..100010,0..30] of longint;
var n,m,i,j,k,z,x,y:longint;
var v:array[0..100010] of boolean;
procedure add(x,y,z:longint);
begin
  inc(m);c[m]:=z;b[m]:=y;ne[m]:=f[x];f[x]:=m;
end;
function log(x:longint):longint;
begin
  exit(trunc(ln(x)/ln(2)));
end;
procedure dfs(dep,num:longint);
var j:longint;
begin
  v[num]:=true;j:=f[num];d[num]:=dep;
  while j>0 do
  begin
    if not v[b[j]] then
    begin
      p[b[j]]:=p[num]+c[j];
      dfs(dep+1,b[j]);fa[b[j],0]:=num;
    end;
    j:=ne[j];
  end;
end;
function lca(x,y:longint):longint;
var t,i,j,k:longint;
begin
  if d[x]<d[y] then
  begin
    t:=x;x:=y;y:=t;
  end;
  k:=log(n);
  for i:=k downto 0 do if d[x]-1<<i>=d[y] then x:=fa[x,i];
  if x=y then exit(x);
  for i:=k downto 0 do
  begin
    if fa[x,i]<>fa[y,i] then
    begin
      x:=fa[x,i];y:=fa[y,i];
    end;
  end;
  exit(fa[x,0]);
end;
begin
  readln(n);
  fillchar(f,sizeof(f),255);
  for i:=1 to n-1 do
  begin
    readln(x,y,z);
    add(x,y,z);add(y,x,z);
  end;
  dfs(1,0);k:=log(n);
  for i:=1 to k do
  for j:=1 to n do fa[j,i]:=fa[fa[j,i-1],i-1];
  readln(m);
  for i:=1 to m do
  begin
    readln(x,y);
    writeln(p[x]+p[y]-p[lca(x,y)]*2);
  end;
end.

 

 

欢迎转载,若转载请注明出处.

原文地址:https://www.cnblogs.com/HAdolf-HQY/p/6389609.html