Pascal 倍增求LCA

本文介绍了一种用于查找树中两个节点最低公共祖先(LCA)的高效算法,该算法的预处理时间为O(nlog(n)),查询时间为O(log(n))。文章详细解释了算法的工作原理,并提供了Delphi语言实现的源代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<pre name="code" class="delphi">{
       效率  预处理 O(nlog(n)) 查询 O(log(n))
             优点:能够记录路径、
	     缺点:没有LCA转RMQ的ST算法快
}
program pro;
var
        link:array[0..100]of record ke,po,ne,pr:longint; end;
        deep,st:array[0..100]of longint;
        fa:array[0..100,0..20]of longint;
        n,m,tot,i,j:longint;

procedure make(u,v:longint);//链表存储树
begin
        inc(tot);
        link[tot].ne:=st[u];
        st[u]:=tot;
        link[tot].po:=v;
end;

procedure swap(var x,y:longint);
var
        kk:longint;
begin
        kk:=x; x:=y; y:=kk;
end;

procedure init;
var
        u,v,c,ii:longint;
begin
        readln(n);
        for ii:=1 to n-1 do
        begin
                readln(u,v);
                make(u,v);
        end;
end;

function find(x,y:longint):longint;//查找  效率 O(log(n))
var
        temp,ii:longint;
begin
        if x=y then exit(x);									
        if deep[x]<deep[y] then swap(x,y);//先将两点移到同一深度
        temp:=deep[x]-deep[y];
        ii:=0;
        while temp>0 do
        begin
                if temp and 1=1 then x:=fa[x,ii];				
                temp:=temp shr 1;
                inc(ii);
        end;
        if x=y then exit(x);

        ii:=0;
        while x<>y do <span style="white-space:pre">	</span>//以 2^ii 向上查找
        begin
                if (fa[x,ii]<>fa[y,ii])or((fa[x,ii]=fa[y,ii])and(ii=0)) then	
                begin				   //到每一个 2^ii 的父亲结点  如果 下一个2^k结点相等则dec(ii)查找当前结点距离2^k的父亲结点
                        x:=fa[x,ii]; y:=fa[y,ii];
                        inc(ii);
                end
                else dec(ii);
        end;
        exit(x);
end;

procedure ready(x:longint); //预处理
var
        temp,po,son,ii:longint;
begin
        temp:=st[x];
        while temp<>0 do							
        begin
                son:=link[temp].po;									
                fa[son,0]:=x;
                po:=x;
                deep[son]:=deep[x]+1;
                ii:=0;
                while fa[po,ii]<>0 do
                begin
                        fa[son,ii+1]:=fa[po,ii];//递归求出距离当前结点2^ii的父亲节点
                        po:=fa[po,ii];
                        inc(ii);
                end;
                ready(son);
                temp:=link[temp].ne;//向下递归求解
        end;
end;

begin
assign(input,'test.in');reset(input);
assign(output,'test.out');rewrite(output);
        init;
        ready(1);
        for i:=1 to n do
        for j:=1 to n do
        writeln(i,' ',j,' ',find(i,j));
close(input);
close(output);
end.




                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值