WikiOI 2370 小机房的树 (最裸LCA)

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.

你可能感兴趣的:(LCA)