原题
题目描述 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.
欢迎转载,若转载请注明出处.