【Description】
某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间。
假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇之间都有道路连接,任意两个城镇之间如果有直连道路,在他们之间行驶需要花费单位时间。该国公路网络发达,从首都出发能到达任意一个城镇,并且公路网络不会存在环。
你的任务是帮助该商人计算一下他的最短旅行时间。
【Input】
输入文件中的第一行有一个整数
N
,
【Output】
在输出文件中输出该商人旅行的最短时间。
【Sample Input】
5
1 2
1 5
3 5
4 5
4
1
3
2
5
【Sample Output】
7
【题解】
题意很清楚,求起点至终点每两个点的最短路径之和,而这个图退化成了一棵树,我们可以想到求出两点的
LCA
再进行根据深度计算。具体来说,在以T为根的树中,对于两点
u
,
参考代码如下:
type struct = record
go,next:longint;
end;
var n,m,ans,cnt,cntr:longint;
a:array[0..60200] of struct; //存储边
en,enr,father,depth:array[0..30100] of longint;
visited:array[0..30100] of boolean; //存储访问记录
road:array[0..30100] of struct; //存储询问
procedure addedge(u,v:longint); //增加一条边
begin
inc(cnt); a[cnt].go:=v; a[cnt].next:=en[u]; en[u]:=cnt;
end;
procedure addroad(u,v:longint); //增加一个询问
begin
inc(cntr); road[cntr].go:=v; road[cntr].next:=enr[u]; enr[u]:=cntr;
end;
procedure init; //读入边
var i,x,y:longint;
begin
readln(n);
fillchar(a,sizeof(a),0);
for i:=1 to n-1 do begin
readln(x,y); addedge(x,y); addedge(y,x);
end;
end;
function getfather(x:longint):longint;
begin
if father[x]<>x then father[x]:=getfather(father[x]);
exit(father[x]);
end;
procedure tarjan(x,fa:longint); //朴素Tarjan算法
var i,tmp,t1,t2,t3:longint;
begin
father[x]:=x;
i:=en[x];
while (i<>0) do begin
tmp:=a[i].go;
i:=a[i].next;
if tmp=fa then continue;
tarjan(tmp,x);
father[tmp]:=x;
end;
visited[x]:=true;
i:=enr[x];
while (i<>0) do begin
tmp:=road[i].go;
i:=road[i].next;
if visited[tmp] then begin
t1:=getfather(tmp);
inc(ans,depth[x]+depth[tmp]-2*depth[t1]);
end;
end;
end;
procedure calcdep(x,fa:longint); //计算每个点深度(单独计算可提高速度)
var i,tmp:longint;
begin
i:=en[x];
while (i<>0) do begin
tmp:=a[i].go;
i:=a[i].next;
if tmp=fa then continue;
depth[tmp]:=depth[x]+1;
calcdep(tmp,x);
end;
end;
procedure main; //读取询问并计算
var i,t,k:longint;
begin
readln(m); readln(t);
for i:=2 to m do begin
readln(k);
addroad(t,k); addroad(k,t);
t:=k;
end;
fillchar(visited,sizeof(visited),false);
depth[1]:=1;
calcdep(1,1);
tarjan(1,1);
writeln(ans);
end;
begin
init;
main;
end.