lca问题的完美解决和升级!!!——预处理+二分深搜

良好应用:2013noip提高组day1压轴题货车运输

思路:可以明显看出是最大生成树,然后可以想到寻找路径,结果就是路径上的最小值(因为是树,所以路径是唯一的!)

            最后就是如何求路径最小值了,可以先求出lca,同时预处理,完美地解决。

参考网址:程序写得很漂亮

参考程序(一遍过):

var

  v:array[0..111000]of boolean;
  dp,mm:array[0..110000,0..20]of longint;
  a,b,c,f,head,depth:array[0..110000]of longint;
  e:array[0..110000]of record
                        j,w,next:longint;
  end;
  cnt,n,m:longint;
procedure openfile;
begin
  assign(input,'truck.in');reset(input);
  assign(output,'truck.out');rewrite(output);
end;
procedure closfile;
begin
  close(input);close(output);
end;
function min(a,b:longint):longint;
begin
  if a<b then exit(a);
  exit(b);
end;
procedure init;
var
  i:longint;
begin
  readln(n,m);
  for i:=1 to n do f[i]:=i;
  for i:=1 to m do readln(a[i],b[i],c[i]);
end;
procedure kp(l,r:longint);
var
  i,j,x,t:longint;
begin
  i:=l;j:=r;x:=c[l+random(r-l+1)];
  repeat
    while c[i]>x do i:=i+1;
    while c[j]<x do j:=j-1;
    if i<=j then
     begin
       t:=c[i];c[i]:=c[j];c[j]:=t;
       t:=a[i];a[i]:=a[j];a[j]:=t;
       t:=b[i];b[i]:=b[j];b[j]:=t;
       i:=i+1;j:=j-1;
     end;
  until i>j;
  if i<r then kp(i,r);
  if j>l then kp(l,j);
end;
{procedure newcode(u,v,i:longint);
begin
  cnt:=cnt+1;
  e[cnt].cap:=c[i];
  e[cnt].u:=a[i];
  e[cnt].v:=b[i];
end;}
procedure insert(u,v,c:longint);
begin
  cnt:=cnt+1;
  e[cnt].j:=v;e[cnt].w:=c;e[cnt].next:=head[u];head[u]:=cnt;
  cnt:=cnt+1;
  e[cnt].j:=u;e[cnt].w:=c;e[cnt].next:=head[v];head[v]:=cnt;
end;
function find(x:longint):longint;
begin
  if f[x]<>x then f[x]:=find(f[x]);
  exit(f[x]);
end;
procedure kruskal;
var
  i,count,p,q:Longint;
begin
  count:=0;
  for i:=1 to m do
   begin
     p:=find(a[i]);q:=find(b[i]);
     if p<>q then
      begin
        //newcode(a[i],b[i],i);
        //newcode(b[i],a[i],i);
        insert(a[i],b[i],c[i]);
        insert(b[i],a[i],c[i]);
        f[q]:=p;
        count:=count+1;
        if count=n-1 then break;
      end;
   end;
  for i:=1 to n do f[i]:=find(i);
end;
procedure dfs(x,i:longint);
var
  j,k:longint;
begin
  v[x]:=true;depth[x]:=i;
  j:=head[x];
  while j>0 do
   begin
     if not v[e[j].j] then
      begin
        dp[e[j].j,0]:=x;mm[e[j].j,0]:=e[j].w;k:=0;
        while dp[dp[e[j].j,k],k]<>0 do
         begin
           dp[e[j].j,k+1]:=dp[dp[e[j].j,k],k];
           mm[e[j].j,k+1]:=min(mm[e[j].j,k],mm[dp[e[j].j,k],k]);
           k:=k+1;
         end;
        dfs(e[j].j,i+1);
      end;
     j:=e[j].next;
   end;
end;
procedure lca;
var
  i:longint;
begin
  for i:=1 to n do
   if not v[i] then dfs(i,0);
end;
procedure prepare;
begin
  randomize;
  kp(1,m);
  kruskal;
  lca;
end;
function answer(x,y:longint):longint;
var
  t,ans,k:longint;
begin
  if depth[x]<depth[y] then
   begin
     t:=x;x:=y;y:=t;
   end;
  ans:=maxlongint;t:=depth[x]-depth[y];k:=0;
  while t<>0 do
   begin
     if t and 1=1 then
      begin
        ans:=min(ans,mm[x,k]);
        x:=dp[x,k];
      end;
     t:=t shr 1;
     k:=k+1;
   end;
  k:=0;
  while x<>y do
   begin
     if (dp[x,k]<>dp[y,k])or(k=0) then
      begin
        ans:=min(ans,min(mm[x,k],mm[y,k]));
        x:=dp[x,k];y:=dp[y,k];
        k:=k+1;
      end
     else k:=k-1;
   end;
  exit(ans);
end;
procedure solve;
var
  q,from,tt:longint;
begin
  readln(q);
  for q:=1 to q do
   begin
     readln(from,tt);
     if f[from]<>f[tt] then writeln(-1)
      else writeln(answer(from,tt));
   end;
end;
procedure main;
begin
  openfile;
  init;
  prepare;
  solve;
  closfile;
end;
begin
  main;
end.

你可能感兴趣的:(lca问题的完美解决和升级!!!——预处理+二分深搜)