• 树上倍增求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];
    }
  • 相关阅读:
    VirtualBox Linux服务vboxservicetemplate
    oracle 11g常用命令
    haproxy dataplaneapi
    使用jproflier 分析dremio
    cube.js 支持oceanbase 的mysql driver
    fastdfs 集群异常修复实践
    使用jHiccup 分析java 应用性能
    dremio mysql arp 扩展
    cube.js graphql 支持
    apache kyuubi 参考架构集成
  • 原文地址:https://www.cnblogs.com/qywyt/p/9629211.html
Copyright © 2020-2023  润新知