zoukankan      html  css  js  c++  java
  • 最近公共祖先 LCA 模板

    算法步骤

    时间复杂度 (O((n+q)log n))(n)是问题规模,(q)是询问个数
    倍增法求(LCA)
    (fa[i,j])表示从(i)开始向上走(2^j)所能到达的节点 ((0 leq jleqlog n))
    (depth[i])表示节点(i)的深度
    哨兵:如果从(i)开始跳(2^j)步会跳过根节点,那么(fa[i,2^j]=0,depth[0]=0)

    1. 先将两个节点跳到同一层
    2. 让两个节点同时往上跳,一直跳到他们最近公共祖先的下一层。
    #include <bits/stdc++.h>
    using namespace std;
    const int N = 5e5 + 10,UP = 19;// UP = log2(N)
    #define endl '
    '
    #define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
    int e[N*2],ne[N*2],h[N],idx,fa[N][UP + 1],depth[N],n,m,s;
    // 注意这里fa[N][UP + 1],UP必须要+1,不然求lca的时候数组越界
    void add(int a,int b) {
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx ++; 
    }
    void bfs(int root) {
        memset(depth,0x3f,sizeof depth);
        depth[0] = 0,depth[root] = 1;
        queue<int> q;
        q.push(root);
        while(q.size()) {
            int t = q.front();
            q.pop();
            for(int i = h[t]; ~i; i = ne[i]) {// 遍历每个节点的子节点
                int j = e[i];
                if(depth[j] > depth[t] + 1) {// 更新depth数组
                    depth[j] = depth[t] + 1;
                    q.push(j);
                    fa[j][0] = t;//初始化 fa数组
                    for(int k = 1;k <= UP; ++k)
                        fa[j][k] = fa[fa[j][k - 1]][k - 1];
                }
            }
        }
    }
    int lca(int a,int b) {
        if(depth[a] < depth[b]) swap(a,b);// 始终让 a 在更深的一层
        for(int k = UP; k >= 0; --k) {// a开始往上跳,跳到与b同深度
            if(depth[fa[a][k]] >= depth[b]) // 如果a 跳 2^j还没超过 b,就可以更新a当前的位置
                a = fa[a][k];
        }
        if(a == b) return a;// 如果a 和 b在同一层了,并且a == b,说明 这个节点就是他们的LCA
        for(int k = UP;k >= 0; --k) {
            // 初始化的时候,超过根节点的值,都是0,不用担心步子太大跳过祖先
            if(fa[a][k] != fa[b][k]) {// 一起向上跳,如果上一层不相同,就继续跳
                a = fa[a][k];
                b = fa[b][k];
            }
        }
        return fa[a][0];// 在向上跳一步就是a和b的LCA
    }
    
    int main() {
        IO;
        memset(h,-1,sizeof h);
        cin >> n >> m >> s;
        for(int i = 0;i < n - 1; ++i) {
            int a,b;
            cin >> a >> b;
            add(a,b);
            add(b,a);
        }
        bfs(s);
        while(m --) {
            int a,b;
            cin >> a >> b;
            cout << lca(a,b) << endl;
        }
        return 0;
    }
    

    模板题

    P3379 【模板】最近公共祖先(LCA)

  • 相关阅读:
    PHP+JQUEY+AJAX实现分页
    Flume知识扩展
    Flume高级之自定义MySQLSource
    Flume监控之Ganglia
    Flume 概述/企业案例
    Yarn (转自之乎者也)
    MapReduce如何解决数据倾斜?
    JVM调优
    Hive性能优化
    HBase的二级索引
  • 原文地址:https://www.cnblogs.com/lukelmouse/p/12594634.html
Copyright © 2011-2022 走看看