• 倍增lca的另类做法(以空间换取小常数)


    陈锋老师讲到的倍增lca的另类做法。

    众所周知,可以利用利用dfs序判断一个点y是否在点x的子树中(不再赘述)。

    于是在寻找x和y的lca的时候,只需要让深度小的那个点(y)往上倍增爬,直到y的父亲是x的祖先。

    这个原理上比传统算法快了一倍,但是占用了较多的内存。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iomanip>
    #include <cmath>
    #include <queue>
    #include <map>
    using namespace std;
    #define reg register
    #define LL long long
    inline LL read() {
        LL res=0;char ch=getchar();bool fu=0;
        while(!isdigit(ch)) fu|=(ch=='-'), ch=getchar();
        while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
        return fu ? -res : res;
    }
    #define mkp make_pair
    #define pii pair<int, int>
    
    namespace BriMon
    {
    #define N 500005
    int n, m, root;
    struct edge {
        int nxt, to;
    }ed[N<<1];
    int head[N], cnt;
    inline void add(int x, int y) {
        ed[++cnt] = (edge){head[x], y};
        head[x] = cnt;
    }
    int fa[N][21], dep[N];
    int in[N], out[N], dfsc;
    
    bool isancestor(int x, int y)  //x是不是y的祖先 
    {
        return (in[x] <= in[y]) and (out[x] >= out[y]);
    }
    
    inline int lca(int x, int y) {
        if (dep[x] < dep[y]) swap(x, y);
        if (isancestor(y, x)) return y;
        for (reg int i = 20 ; i >= 0 ; i --) if (fa[y][i] and !isancestor(fa[y][i], x)) y = fa[y][i];
        return fa[y][0];
    }
    
    void dfs(int x) 
    {
        in[x] = ++dfsc;
        for (reg int i = head[x] ; i ; i = ed[i].nxt) {
            int to = ed[i].to;
            if (dep[to]) continue;
            dep[to] = dep[x] + 1;
            fa[to][0] = x;
            for (reg int j = 1 ; j <= 20 ; j ++) fa[to][j] = fa[fa[to][j-1]][j - 1];
            dfs(to);
        }
        out[x] = ++dfsc;
    }
    
    signed main() 
    {
        n = read(), m = read(), root = read();
        for (reg int i = 1 ; i < n ; i ++)
        {
            int x = read(), y = read();
            add(x, y), add(y, x);
        }
        dep[root] = 1;
        dfs(root);
        while(m--) printf("%d
    ", lca(read(), read()));
        return 0;
    }
    
    }
    
    signed main()
    {
        BriMon :: main();
        return 0;
    }
  • 相关阅读:
    [经验交流] kubernetes v1.11 更新了高可用方案
    Java泛型和编译优化的一个例子
    Java泛型和编译优化的一个例子
    Java泛型和编译优化的一个例子
    浅析JSONP-解决Ajax跨域访问问题
    java设计原则---开闭原则
    for,foreach,iterator的用法和区别
    List,Set,Map三种接口的区别
    为什么接口中定义的变量必须为常量?
    重写,string创建内存问题
  • 原文地址:https://www.cnblogs.com/BriMon/p/13760759.html
Copyright © 2020-2023  润新知