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.