树上倍增求lca

嗯~ o(* ̄▽ ̄*)o

lca是树上两点的最近公共祖先。如果在同一个分支上就是更靠近根的那个点,否则就是大家一起向上走,第一次能都经过的那个点。

根据这两个性质,我们对于每次询问可以把一个向上走到根节点,标记走过的点。然后从另一个点向上走,直到遇到第一个标记过的点即为lca。

如果整个树是一个长链,这样的方法就会退化成一复杂度为n的算法。我们想一想如何优化成为log的策略。

假设两个节点到达lca的距离是m,那么这个m一定是可以被分解成一个二进制数的(废话)。我们可以好好利用一下这个性质。

设数组fa[i][k]表示节点i向上走2^k的父节点,d[i]表示i节点的深度。那么可以得到fa[i][0]是从i向上走1个到达的节点,即父节点。而且还可以得到fa[i][k]=fa[fa[i][k-1]][k-1],因为二进制的定义。d[i]=d[fa[i][0]]+1应该不用再说了吧。

同时还可以维护许多数组表示其他性质,在topsort的时候需要自己加上。

//传入的参数即为你选中的根节点,实际上这个根节点选什么都一样
t=(int)log(n*1.0)/log(2.0)+1;//为最大的k
void bfs(int now)
{
    stack<int>q;
    q.push(now);d[now]=1;
    while(q.size())
    {
        int x=q.top();q.pop();
        for(int j=link[x];j!=0;j=o[j].next)
        {
            int y=o[j].y;
            if(d[y])continue;
            q.push(y);
            d[y]=d[x]+1;
            fa[y][0]=x;
            for(int k=1;k<=t;k++)
                fa[y][k]=fa[fa[y][k-1]][k-1];//类似于动态规划的转移呦
        }
    }
}

然后对于每个询问,先把x向上调整到于y同一深度,如果在同一个链上这个时候应该已经遇到了吧。如果没有遇到就可以俩人一起向上走,知道fa[x][k]==fa[y][k]的时候停下来。

int lca(int x,int y)
{
    if(d[x]>d[y])
        swap(x,y);
    for(int k=t;k>=0;k--)
        if(d[fa[y][k]]>=d[x])
            y=fa[y][k];
    if(x==y)return x;
    for(int k=t;k>=0;k--)
        if(fa[x][k]!=fa[y][k])
            x=fa[x][k],y=fa[y][k];
    return fa[x][0];
}

 

转载于:https://www.cnblogs.com/qywyt/p/9629211.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值