ACM_lca

前言

这里写图片描述
lca(Least Common Ancestors) : 最近公共祖先, 一般题目的是给你一棵树(当然也有些题不会直接给你)题目的解法大多会让你向上找两个点的最近公共祖先, 比如上图的4 和 5的公共祖先是2, 9 和 7 的公共祖先是3, 3 和 8的公共祖先是3, 搭配的可能就还有一些其他的问题, 比如两点间的最短距离(边有权值, 而且边的权值可能会变) 或者搭配树形DP类似的东西
lca的解法我现在了解的有5种:

lca的5种解法

  1. 暴力: 复杂度O(n) 适合查询不多的情况
    比较直接的方法, 它的适用范围在与询问很少的时候, 思想也很简单, 我们需要知道两个东西:
    1.每个点的父亲(因为是树, 所以每个点的父亲只有1个)
    2 每个点的深度, 就是DFS的时候它的深度, 比如上图中1的深度是0 然后 2和3的深度是1 然后 4, 5, 6, 7的深度是2…….(我是从0开始算的, 当然1也是ok的)
    知道这两个东西之后 现在我们查找一对数的lca 只需要把他们先提升到同一深度, 然后2个数一起向上, 直到两个数相等, 那么这个相等的数就是他们的lca
    还是这个图这里写图片描述
    比如我们找8和7的lca(方便描述假如x = 8, y = 7, x, y是变量)
    1.找到每个点的父亲和深度
    这里写图片描述如图
    2.把他们提到同一深度
    我们发现8的深度更深, 于是把8向上提, x = pa[8] = 6
    再检查我们发现x和y的深度一样了(都是2)
    3.向上找公共祖先
    把他们一起向上提直到x == y
    所以操作是x = pa[x] = 3, y = pa[y] = 3;
    此时发现x == y了, 好了那么此时的x(也就是3) 就是他们的公共祖先了
    大致代码如下:
    第一个: 找深度和父亲的DFS:

    void dfs(int u, int f, int d) {
    dep[u] = d;
    for(int i = 0; i < son[u].size(); ++i) {
        int v = son[u][i];
        if(v == f) continue;
        dfs(v, u, d+1);
        pa[v] = u;
    }
    }

    我这里用的是邻接表存的, 当然也可以用其他方式, 链式前向星其实不错, 貌似更快?

    第二个:找lca

    int lca(int x, int y) {
    if(dep[x] < dep[y]) swap(x, y);
    while(dep[x] > dep[y]) x = pa[x];
    while(x != y) {
        x = pa[x];
        y = pa[y];
    }
    return x;
    }

    如此 只要调用lca(7, 8) 就可以找到7和8的lca了;
    由于dfs每个点只访问一次, 找父亲最多找n(点的个数)次, 所以复杂度是O(n)

  2. 倍增: 建图的时候复杂度是O(nlongn)查询的时候是O(logn)
    倍增就是二分的思想, 和第一种的暴力有很多相似的地方, 不过优化了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值