lca

http://unbelievable.ycool.com/post.982865.html

 

有两种方法的... 这里先搞定一种方法吧...
d[i] 表示 i节点的深度
p[i,j] 表示  i 的 2^j 倍祖先
那么就有一个递推式子  p[i,j]=p[p[i,j-1],j-1]
这样子 一个 o(n log n) 的预处理 求出 每个节点的 2^k 的祖先

然后 对于每一个 询问的点对a b 的最近公共祖先 就是:

先判断是否 d[a]>d[b]  如果是的话就交换一下(保证 a 的深度小于 b 方便下面的操作)

然后把b 调到与a 同深度

同深度以后再 把a b 同时往上调(dec(j)) 调到有一个最小的j 满足 p[a,j]=p[b,j] (a b 是在不断更新的)

最后再把 a b 往上调 (a=p[a,0] b=p[b,0]) 一个一个向上调 直到 a=b

这时 a or b 就是他们的 最近公共祖先

 

{建树时
p[i,0]:=father[i]
同时记录好d[i]
}
procedure prepare;
var k, i, j : longint;
begin
  k:=1; j:=0;
  while k<n do begin
    inc(j); k:=k+k;
    for i:=1 to n p[i,j]:=p[p[i,j-1],j-1];
  end;
  power:=k; limit:=j;
end;

function lca(a, b : longint): longint;
var i, j, t : longint;
begin
  if d[a]>d[b] then begin t:=a; a:=b; b:=t; end;
  i:=limit; j:=power;
  while d[b]>d[a] do begin
    if d[b]-j>=d[a] then b:=p[b,i];
    dec(i); j:=j div 2;
  end;
  i:=limit;
  while (a<>b) and (i>=0) do begin
    if p[a,i]<>p[b,i] then begin
      a:=p[a,i]; b:=p[b,i];
    end;
    dec(i);
  end;
  while a<>b do begin
    a:=p[a,0]; b:=p[b,0];
  end;
  lca:=a;
end;


posted @ 2008-12-05 15:34  jesonpeng  阅读(159)  评论(0)    收藏  举报