LCA的求法和扩展

求解树上LCA(最近公共祖先)

11,朴素dfs(形象的说就是:爬!)

思路:

  • 从两个点开始,先把深度更深的节点爬到两个节点相同的地步
  • 两个节点一起上移,直到同一深度
  • 过于直白,过程略

22,在线:倍增跃迁

规定: d e p [ 0 ] = 0 dep[0]=0 dep[0]=0(哨兵),默认lca第一个参的 d e p [ x ] dep[x] dep[x] ≧ \geqq d e p [ y ] dep[y] dep[y]否则交换

预处理:

  • 树的深度,log表,任意节点向上跳2的幂次方步的终点
  • f a [ x ] [ i ] fa[x][i] fa[x][i] f a [ x ] [ i ] fa[x][i] fa[x][i] 表示节点 x x x 上跳 2 i 2^i 2i 级的节点编号
  • 最关键的转移方程是: f a [ x ] [ i ] = f a [ f a [ x ] [ i − 1 ] ] [ i − 1 ] f a [ x ] [ i ] = f a [ f a [ x ] [ i − 1 ] ] [ i − 1 ] fa[x][i]=fa[ fa[x][i-1] ][i-1]fa[x][i]=fa[fa[x][i−1]][i−1] fa[x][i]=fa[fa[x][i1]][i1]fa[x][i]=fa[fa[x][i1]][i1]
    即: x x x 的第 i i i个祖先是 x x x 的第 2 i − 1 2^{i-1} 2i1 个祖先的第 2 i − 1 2^{i-1} 2i1个祖先。
    注意:初始化跃迁表的时候,k从1开始!!!!
void dfs(int f,int p)  传参父节点和当前节点
{
	dep[p]=dep[f]+1;
	fa[p][0]=f;
	for(int i=1;i<=(maxlog也可以)logn[dep[p]];i++)fa[p][i]=fa[fa[p][i-1]][i-1];
	for(int i=h[p];~i;i=nxt[i])if(to[i]!=f)dfs(p,to[i]);
}

求lca:

  • 1,低深度节点跳到和高深度同一深度
  • 2,同一深度的节点同时上跳,直到lca的下一层
int lca(int x,int y)
{
	if(dep[x]<dep[y])swap(x,y);  
	
	for(int k=maxlog;k>=0;k--)
	if(dep[fa[x][k]]>=dep[y])x=fa[x][k];   保证同深度
	
	if(x==y)return x;
	
	for(int k=maxlog;k>=0;k--)
		if(f[x][k]!=fa[y][k])
			x=f[x][k],y=fa[y][k];           倍增树上跃迁
	
	return fa[x][0];
} 

33,tarjan:离线

使用LCA

大部分情况下我们会对倍增情有独钟,因为不光在LCA的过程中很不错,这种稀疏表的思想还能解决书上两点最大值,这一点是树剖达不到的,因为有的点间不过根

最长树边的长度

对LCA进行简单的修改

void dfs_tree(int x,int par)
{

    dep[x]=dep[par]+1;
    rep(i,1,9)
    {
        f[x][i]=f[f[x][i-1]][i-1];
        g[x][i]=max(g[f[x][i-1]][i-1],g[x][i-1]);
    }

    for (int i=h[x];~i;i=nxt[i])
    {
        if(e[i]!=par)
        {
            f[e[i]][0]=x;
            g[e[i]][0]=v[i];
            dfs_tree(e[i],x);
        }
    }
}

double lca(int x,int y)
{
    double ans= 0.0;

    if(dep[x]<dep[y])swap(x,y);

    for(int i=9;i>=0;i--)
    {
        if(dep[f[x][i]]>=dep[y])
        {
            ans=max(ans,g[x][i]);
            x=f[x][i];
            if(x==y)return ans;
        }
    }

    for(int i=9;i>=0;i--)
    {
        if(f[x][i]!=f[y][i])
        {
            ans=max(ans,g[x][i]);
            x=f[x][i];
            ans=max(ans,g[y][i]);
            y=f[y][i];
        }
    }
    return max(ans,max(g[x][0],g[y][0]));

}

这里的LCA就可以返回树上(x,y)间的最长树边长了
Link 以上使用的实际例子

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流苏贺风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值