最近公共祖先 LCA 倍增算法

最近公共祖先 LCA 倍增算法

倍增算法可以在线求树上两个点的LCA,时间复杂度为nlogn

预处理:通过dfs遍历,记录每个节点到根节点的距离dist[u],深度d[u]

init()求出树上每个节点u的2^i祖先p[u][i]

求最近公共祖先,根据两个节点的的深度,如不同,向上调整深度大的节点,使得两个节点在同一层上,如果正好是祖先结束,否则,将连个节点同时上移,查询最近公共祖先。

void dfs(int u){
    for(int i=head[u];i!=-1;i=edge[i].next){
        int to=edge[i].to;
        if(to==p[u][0])continue;
        d[to]=d[u]+1;
        dist[to]=dist[u]+edge[i].w;
        p[to][0]=u; //p[i][0]存i的父节点
        dfs(to); 
    }
}

i的2^j祖先就是i的(2^(j-1))祖先的2^(j-1)祖先:

void init(){
    for(int j=1;(1<<j)<=n;j++){
        for(int i=1;i<=n;i++){
            p[i][j]=p[p[i][j-1]][j-1];
        }
    }
}

LCA:

int lca(int a,int b){
    if(d[a]>d[b])swap(a,b); //b在下面 
    int f=d[b]-d[a];//f是高度差
    for(int i=0;(1<<i)<=f;i++){//(1<<i)&f找到f化为2进制后1的位置,移动到相应的位置
        if((1<<i)&f)b=p[b][i];//比如f=5(101),先移动2^0祖先,然后再移动2^2祖先
    }
    if(a!=b){
        for(int i=(int)log2(N);i>=0;i--){
            if(p[a][i]!=p[b][i]){//从最大祖先开始,判断a,b祖先,是否相同
                a=p[a][i]; b=p[b][i];//如不相同,a b同时向上移动2^j
            }
        }
        a=p[a][0];//这时a的father就是LCA
    }
    return a;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值