zoukankan      html  css  js  c++  java
  • 树上倍增

    提到树上倍增就不得不先说说最近公共祖先(LCA)了

    如下图所示

    ④和⑤的LCA即为②(绿色的)

    那怎么求LCA呢?

    最简单粗暴的方法就是先深搜一次,处理出每个点的深度

    然后把深度更深的那一个点④一个点地一个点地往上跳,直到到某个点③和另外那个点⑤的深度一样

    然后两个点一起一个点地一个点地往上跳,直到到某个点(就是LCA)时两个点重合

    不过大家应该发现一个点地一个点地跳时间复杂度会很高    

    如果一下子跳到目标点内存又不支持

    所以神犇们找到了一种新的算法--树上倍增

    时间复杂度为O(n*logn)

    树上倍增思路

    先比较两个点的深度,如果深度不同,先让深的点往上跳,浅的先不动,等两个点深度一样时,如果是同一点直接返回,如果是不同点进行下一步:如果不同,两个点一起跳,j从大到小枚举(j不用太大),如果两个点都跳这么多后,得到的点相等,两个点都不动(因为有可能正好是LCA也有可能在LCA上方),直到得到的点不同,就可以跳上来,然后不断跳,因此两个点都在LCA下面那层,所以再跳1步即可到达LCA

    整体思路图

    状态转移方程

    f[i][j]表示节点i往上跳2^j次后的节点 
    可以转移为 
    f[i][j] = f[f[i][j-1]][j-1]

    (此处注意循环时先循环j,再循环i)

    至于为啥自行理解

    此处是核心代码

     1 int lca(int x,int y){
     2     if(dep[x] < dep[y]) swap(x,y);//保证x比y深
     3     for(int i = 20;i >= 0;i--)
     4         if(dep[x] - (1<<i) >= dep[y]) x = fa[x][i];//深的先跳
     5              //1<<i表示把1向左移i位,类似于2的累乘器
     6     if(x == y) return x;
     7       //若深的跳完刚好与浅的那个重合,则直接输出
     8     for(int i = 20;i >= 0;i--)
     9         if(fa[x][i] != fa[y][i])
    10     {
    11             x = fa[x][i];
    12             y = fa[y][i];
    13         }
    14     return fa[x][0];//0 是再跳一步
    15 }

    树上倍增还可以有很多变化,这使得它可以有更多的变化。

    可以用来维护各结点的各个数据

    比如用l[i][j]记录i到他的第2^j个父亲的路径长度,就可以边求LCA边求出两点距离,因为l[i][j]满足倍增的递推式:

    l[i][j] = l[i][j-1] + l[fa[i][j-1]][j-1]

    或者用maxlen[i][j]记录i到第2^j个父亲的路径上最长边的边权,它满足

    maxlen[i][j] = max{maxlen[i][j-1], maxlen[fa[i][j-1]][j-1]},这样就可以快速求出两点路径上最长边的边

    例题!!!

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

    https://www.luogu.org/problem/show?pid=3379

    POJ 1986 Distance Queries

    http://poj.org/problem?id=1986

    HDU 3078 Network

    http://acm.hdu.edu.cn/showproblem.php?pid=3078

    HDU 2586 How far away ?

    http://acm.hdu.edu.cn/showproblem.php?pid=2586

  • 相关阅读:
    Beta冲刺置顶随笔
    Beta总结
    用户试用与调查报告
    Beta冲刺第七天
    Beta冲刺第六天
    Beta冲刺第五天
    Beta冲刺第四天
    Beta冲刺第三天
    Beta冲刺第二天
    爬虫基本操作
  • 原文地址:https://www.cnblogs.com/thx666/p/8495218.html
Copyright © 2011-2022 走看看