本题中题目叙述没有给出,但是测试数据中默认的条件为:本题的图必为一棵树!否则是不可能在1s的时间内实现的。
知道了这是一棵树,那么下面的问题就简单了:我们只需要求出询问的两个点的LCA。
求LCA有三种算法:一种是离线Tarjan算法,一种是在线O(n^2)-O(1)算法,还有一种是离线的+-1RMQ算法。
我采用的是Tarjan算法,唯一的缺点是非递归方法太难,pascal要加编译开关,否则会导致栈溢出。
下面贴一段Tarjan算法求LCA的pascal代码:
Procedure Tarjan(i:Longint);
var j,k:Longint;
begin
j:=last[i];
while j<>0 do
begin
k:=other[j];
if k<>father[i] then
begin
father[k]:=i;
Tarjan(k);
Union(i,k);
color[Root(i)]:=i;
end;
j:=pre[j];
end;
v[i]:=true;
j:=la[i];
while j<>0 do
begin
k:=ot[j];
if v[k] then LCA[i,k]:=color[Root(k)];
j:=pr[j];
end;
end;
下面是程序:
{$M 100000000}
Program POJ1986;//By_Poetshy
Const
maxn=40005;
Var
i,j,k,m,n :Longint;
kset,dist,father :Array[0..maxn]of Longint;
pre,other,last,long :Array[0..maxn*2]of Longint;
pr,ot,la,ans,color :Array[0..maxn]of Longint;
v :Array[0..maxn]of Boolean;
p,q :Longint;
Procedure Dfs(i:Longint);
var j,k:Longint;
begin
j:=last[i];
while j<>0 do
begin
k:=other[j];
if not v[k] then
begin
dist[k]:=dist[i]+long[j];
v[k]:=true;
Dfs(k);
end;
j:=pre[j];
end;
end;
Function Root(i:Longint):Longint;
begin
if kset[i]=i then exit(i);
kset[i]:=Root(kset[i]);
exit(kset[i]);
end;
Procedure Union(i,j:Longint);
var x,y:Longint;
begin
x:=root(i);y:=root(j);
if x=y then exit else kset[x]:=y;
end;
Procedure Tarjan(i:Longint);
var j,k,p,q:Longint;
begin
j:=last[i];
while j<>0 do
begin
k:=other[j];
if father[i]<>k then
begin
father[k]:=i;
Tarjan(k);
Union(i,k);
Color[Root(i)]:=i;
end;
j:=pre[j];
end;
v[i]:=true;
j:=la[i];
while j<>0 do
begin
k:=ot[j];
if k=i then
begin
ans[j]:=0;
if odd(j) then ans[j+1]:=0 else ans[j-1]:=0;
end else
if v[k] then ans[j]:=dist[i]+dist[k]-2*dist[Color[Root(k)]];
j:=pr[j];
end;
end;
BEGIN
readln(n,m);
for i:=1 to m do
begin
readln(p,q,j);
inc(k);pre[k]:=last[p];last[p]:=k;other[k]:=q;long[k]:=j;
inc(k);pre[k]:=last[q];last[q]:=k;other[k]:=p;long[k]:=j;
end;
for i:=1 to n do kset[i]:=i;
readln(m);k:=0;
for i:=1 to m do
begin
readln(p,q);
inc(k);pr[k]:=la[p];la[p]:=k;ot[k]:=q;
inc(k);pr[k]:=la[q];la[q]:=k;ot[k]:=p;
end;
fillchar(v,sizeof(v),0);
dist[1]:=0;v[1]:=true;
Dfs(1);
fillchar(v,sizeof(v),0);
father[1]:=0;
Tarjan(1);
for i:=1 to m do
if ans[i<<1]=0 then ans[i*2]:=ans[i*2-1] else ans[i*2-1]:=ans[i<<1];
for i:=1 to m do writeln(ans[i*2]);
END.