2370 小机房的树
时间限制: 1 s
空间限制: 256000 KB
题目等级 : 钻石 Diamond
题解
题目描述 Description
小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上。有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力。已知从某个节点爬到其父亲节点要花费 c 的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要你设计一个程序来找到这条路,要求你告诉他们最少需要花费多少精力
输入描述 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之后写的第一道练习题,很裸,但是很基础,很多后来写的lca也是从这一题的代码演变出来的。
program mys;
type ab=^node;
node=record
data,ends:longint;
next:ab;
end;
var x,y,z,u,v,i,j,k,m,n:longint;
f,d,c:array[0..50000]of longint;
dp:array[0..50000,0..30] of longint;
b:array[0..50000]of boolean;
p,a,pa,pp:array[0..50000]of ab;
procedure add(x,y,z:longint);
var i:ab;
begin
i:=p[x];
new(p[x]);
p[x]^.data:=z;
p[x]^.ends:=y;
p[x]^.next:=i;
end;
procedure dfs(x:longint);
var i:ab;
y:longint;
begin
b[x]:=true;
i:=p[x];
while i<>nil do
begin
if b[i^.ends]=false then
begin
f[i^.ends]:=x;
d[i^.ends]:=d[x]+1;
c[i^.ends]:=c[x]+i^.data;
dfs(i^.ends);
end;
i:=i^.next;
end;
b[x]:=false;
end;
function lca(u,v:longint):longint;
var i:longint;
begin
if d[u]then
begin
i:=u;
u:=v;
v:=i;
end;
i:=30;
while d[u]>d[v] do
begin
while d[dp[u,i]]do dec(i);
u:=dp[u,i];
end;
if u=v then exit(u);
i:=30;
while i>=0 do
begin
while (i>=0) and(dp[u,i]=dp[v,i]) do dec(i);
if i>=0 then
begin
u:=dp[u,i];
v:=dp[v,i];
end;
end;
exit(f[u]);
end;
begin
readln(n);
fillchar(f,sizeof(f),0);
for i:=1 to n do
f[i-1]:=i-1;
for i:=1 to n-1 do
begin
readln(u,v,z);
add(u,v,z);
add(v,u,z);
end;
dfs(0);
for i:=1 to n do
dp[i-1,0]:=f[i-1];
for j:=1 to 30 do
for i:=1 to n do
dp[i-1,j]:=dp[dp[i-1,j-1],j-1];
readln(m);
for i:=1 to m do
begin
readln(x,y);
z:=lca(x,y);
writeln(c[x]+c[y]-2*c[z]);
end;
end.