您的位置:首页 > 其它

NOIP2013 D1 T3 货车运输 树上倍增lca+Kruskal

2016-05-18 20:24 567 查看
分析:先跑一边最大生成树,然后进行树上倍增求lca。

g[i,j]表示节点i的第2^j个祖先。w[i,j]表示节点i到第2^j个祖先的路上的最小值。

代码:

const
maxn=10000;
maxm=50000;

var
n,e,maxd,m:longint;
a:array[0..maxm,1..3] of longint;
g,w:array[1..maxn,0..16] of longint;
last,f,d,fa,value:array[1..maxn] of longint;
side:array[1..maxn*2] of record
x,y,z,next:longint;
end;

procedure init;
var
i,x,y,z:longint;
begin
readln(n,m);
for i:=1 to m do
begin
readln(x,y,z);
a[i,1]:=x; a[i,2]:=y; a[i,3]:=z;
end;
end;

procedure qsort(l,r:longint);
var
i,j,k:longint;
begin
if l>=r then exit;
i:=l;
j:=r;
k:=a[(i+j) div 2,3];
repeat
while a[i,3]>k do inc(i);
while a[j,3]<k do dec(j);
if i<=j then
begin
a[0]:=a[i];a[i]:=a[j];a[j]:=a[0];
inc(i);dec(j);
end;
until i>j;
qsort(i,r);
qsort(l,j);
end;

function find(x:longint):longint;
begin
if f[x]=x then exit(x);
find:=find(f[x]);
f[x]:=find;
end;

procedure add(x,y,z:longint);
begin
inc(e);
side[e].x:=x; side[e].y:=y; side[e].z:=z;
side[e].next:=last[x]; last[x]:=e;
inc(e);
side[e].x:=y; side[e].y:=x; side[e].z:=z;
side[e].next:=last[y]; last[y]:=e;
end;

procedure kruskal;
var
i:longint;
begin
for i:=1 to n do
f[i]:=i;
for i:=1 to m do
if find(a[i,1])<>find(a[i,2]) then
begin
add(a[i,1],a[i,2],a[i,3]);
f[find(a[i,1])]:=find(a[i,2]);
end;
end;

procedure dfs(x,dep:longint);
var
i:longint;
begin
if dep>maxd then maxd:=dep;
d[x]:=dep;
i:=last[x];
while i>0 do
with side[i] do
begin
if y<>fa[x] then
begin
fa[y]:=x;
value[y]:=z;
dfs(y,dep+1);
end;
i:=next;
end;
end;

function min(x,y:longint):longint;
begin
if x<y then exit(x)
else exit(y);
end;

procedure bz;
var
i,j:longint;
begin
for i:=1 to n do
if fa[i]>0
then begin
g[i,0]:=fa[i];
w[i,0]:=value[i];
end
else begin
g[i,0]:=-1;
w[i,0]:=maxlongint div 3;
end;
maxd:=trunc(ln(maxd)/ln(2));
for j:=1 to maxd do
for i:=1 to n do
if g[i,j-1]>-1
then begin
g[i,j]:=g[g[i,j-1],j-1];
w[i,j]:=min(w[i,j-1],w[g[i,j-1],j-1]);
end
else begin
g[i,j]:=-1;
w[i,j]:=maxlongint div 3;
end;
end;

function lca(x,y:longint):longint;
var
i:longint;
begin
if find(x)<>find(y) then exit(-1);
if d[x]<d[y] then
begin
x:=x xor y; y:=x xor y; x:=x xor y;
end;
lca:=maxlongint div 3;
for i:=maxd downto 0 do
if (g[x,i]>-1)and(d[g[x,i]]>=d[y]) then
begin
lca:=min(w[x,i],lca);
x:=g[x,i];
end;
for i:=maxd downto 0 do
if g[x,i]<>g[y,i] then
begin
lca:=min(lca,w[x,i]);
lca:=min(lca,w[y,i]);
x:=g[x,i];
y:=g[y,i];
end;
if x=y then exit;
lca:=min(lca,value[x]);
lca:=min(lca,value[y]);
end;

procedure main;
var
i,q,x,y:longint;
begin
qsort(1,m);
kruskal;
for i:=1 to n do
if fa[i]=0 then dfs(i,1);
bz;
readln(q);
for i:=1 to q do
begin
readln(x,y);
writeln(lca(x,y));
end;
end;

begin
init;
main;
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: