LCA倍增算法的错误与模板

先上我原来的错误的代码

type
  node=^link;
  link=record
    num:int64;
    next:node;
  end;

var
 fa:array[0..300000,0..100] of int64;
 dep:array[0..300000] of int64;
   nd:array[0..300000] of node;
  b:array[0..300000] of boolean;
  dl:array[0..300000] of int64;
 n,m,maxdep,ans,t1,t2:int64;
 i:longint;

 procedure maketree;
 var
  t1,t2,head,tail:int64;
  i,j:longint;
  p:node;
   begin
    

     for i:=0 to n do
       b[i]:=false;

     for i:=1 to n-1 do
       begin
         read(t1,t2);
           
         new(p);
         p^.num:=t2;p^.next:=nd[t1];nd[t1]:=p;
         new(p);
         p^.num:=t1;p^.next:=nd[t2];nd[t2]:=p;
       end;

      new(p);
      head:=1;tail:=1;dl[head]:=1;b[1]:=true;
       while head<=tail do
         begin
           p:=nd[dl[head]];

           while p<>nil do
             begin
               if b[p^.num]=false then
                 begin
                   inc(tail);
                   dl[tail]:=p^.num;
                   fa[p^.num,0]:=dl[head];
                   dep[p^.num]:=dep[dl[head]]+1;
                   b[p^.num]:=true;
                   if dep[p^.num]>maxdep then maxdep:=dep[p^.num];
                 end;
               p:=p^.next;
             end;

           inc(head);
         end;

      for j:=1 to trunc(ln(maxdep)/ln(2))+1 do
        for i:=0 to n do
          if dep[i]>=1<<j then
            fa[i,j]:=fa[fa[i,j-1],j-1];
   end;

  procedure lca(a,b:longint);
  var
   i,t:longint;
    begin
      if dep[a]>dep[b] then
        begin
          t:=a;
          a:=b;
          b:=t;
        end;

      if dep[a]<>dep[b] then
        for i:=trunc(ln(dep[b]-dep[a])/ln(2)) downto 0 do
          if dep[b]-1<<i>=dep[a] then
            begin
               b:=fa[b,i];
               ans:=ans+1<<i;
            end;

     if a<>b then
      for i:=trunc(ln(dep[a])/ln(2)) downto 0 do
        if fa[a,i]<>fa[b,i] then
          begin
            a:=fa[a,i];
            b:=fa[b,i];
            ans:=ans+1<<(i+1);
          end;

      if a<>b then inc(ans,2);
    end;

  begin
  
    readln(n);

    if n=1 then
      begin
        writeln(0);
        halt; 
      end;

    maketree;

    readln(m);

    read(t1);
    for i:=2 to m do
      begin
        read(t2);
     
        lca(t1,t2);
        t1:=t2;
      end;

    writeln(ans);
    

  end.

这个写法WA了一个点,答案比标准答案大。

最后发现可能是ln出现了误差,导致结果偏小,使两点无法移到同层。在后面的移动中无论怎样都无法移到同点,使答案比原来大二

改正后的模板

type
  node=^link;
  link=record
    num:int64;
    next:node;
  end;

var
 fa:array[0..300000,0..100] of int64;
 dep:array[0..300000] of int64;
   nd:array[0..300000] of node;
  b:array[0..300000] of boolean;
  dl:array[0..300000] of int64;
  n,m,maxdep,ans,t1,t2:int64;
  i:longint;

 procedure maketree;
 var
  t1,t2,head,tail:int64;
  i,j:longint;
  p:node;
   begin
    

     for i:=0 to n do
       b[i]:=false;

     for i:=1 to n-1 do
       begin
         read(t1,t2);
           
         new(p);
         p^.num:=t2;p^.next:=nd[t1];nd[t1]:=p;
         new(p);
         p^.num:=t1;p^.next:=nd[t2];nd[t2]:=p;
       end;

      new(p);
      head:=1;tail:=1;dl[head]:=1;b[1]:=true;
       while head<=tail do
         begin
           p:=nd[dl[head]];

           while p<>nil do
             begin
               if b[p^.num]=false then
                 begin
                   inc(tail);
                   dl[tail]:=p^.num;
                   fa[p^.num,0]:=dl[head];
                   dep[p^.num]:=dep[dl[head]]+1;
                   b[p^.num]:=true;
                   if dep[p^.num]>maxdep then maxdep:=dep[p^.num];
                 end;
               p:=p^.next;
             end;

           inc(head);
         end;

      for j:=1 to trunc(ln(maxdep)/ln(2))+1 do
        for i:=0 to n do
          if dep[i]>=1<<j then
            fa[i,j]:=fa[fa[i,j-1],j-1];
   end;

  procedure lca(a,b:longint);
  var
   i,t:longint;
    begin
      if dep[a]>dep[b] then
        begin
          t:=a;
          a:=b;
          b:=t;
        end;

      if dep[a]<>dep[b] then
        for i:=trunc(ln(dep[b]-dep[a])/ln(2))+10 downto 0 do
          if dep[b]-1<<i>=dep[a] then
            begin
               b:=fa[b,i];
               ans:=ans+1<<i;
            end;

     if a<>b then
      for i:=trunc(ln(dep[a])/ln(2))+10 downto 0 do
        if fa[a,i]<>fa[b,i] then
          begin
            a:=fa[a,i];
            b:=fa[b,i];
            ans:=ans+1<<(i+1);
          end;

      if a<>b then inc(ans,2);
    end;

  begin
  
    readln(n);

    if n=1 then
      begin
        writeln(0);
        halt; 
      end;

    maketree;

    readln(m);

    read(t1);
    for i:=2 to m do
      begin
        read(t2);
     
        lca(t1,t2);
        t1:=t2;
      end;

    writeln(ans);
    

  end.
原文地址:https://www.cnblogs.com/zhujiangning/p/5252868.html