zoukankan      html  css  js  c++  java
  • 用“倍增法”求最近公共祖先(LCA)

    1.最近公共祖先:对于有根树T的两个结点u、v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u、的祖先且x的深度尽可能大。

    2.朴素算法:记录下每个节点的父亲,使节点u,v一步一步地向上找父亲,直到找到相同的“祖先”,即是所求的答案,时间复杂度O(n)。

    3.优化算法(倍增法):利用二进制的思想,想办法使一步一步向上搜变成以2^k地向上跳所以定义一个P[][]数组,使p[i][j]表示节点i的2^j倍祖先,因此p[i][0]即为i的父亲。我们可以得到一个递推式p[i][j]=p[p[i][j-1]][j-1]。这样子一个O(NlogN)的预处理(dfs)的 2^k 的祖先。定义一个deep[]数组表示节点深度,先判断是否 deep[u] > deep[v]果是的话就交换一下(保证 u的深度小于 v方便下面的操作)然后把u到与v同深度,同深度以后再把u v同时往上调(dec(j)) 调到有一个最小的j 满足: p[u] [j]!=p[v][j],u,v是在不断更新的   最后把u,v 往上调 (u=p[u,0] v=p [v,0]) 一个一个向上调直到   u= v 这时 u or v就是公共祖先。复杂度:O(logn)

     

    下面给出 LCA 的模板:

    输入:第一行:N,M,Q     (因为是一棵树,所以M==N-1)

            接下来M 行: u, v, c ,表示u到v连一条权值为c的边

            接下来Q行:u, v 表示寻求u,v的最近公共祖先,u~v的距离,u~v之间的路径的最大权值

    输出:共Q行,对应上述的询问

     

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cmath>
     5 #include<algorithm>
     6 #include<cstring>
     7 #include<vector>
     8 #include<queue>
     9 using namespace std;
    10 const int maxn=5000;
    11 inline int read(){
    12     int x=0,f=1;char ch=getchar();
    13     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    14     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    15     return x*f;
    16 }
    17 int N,M,Q;
    18 vector<int> to[maxn],cost[maxn];
    19 int p[maxn][50],MAX[maxn][50],sum[maxn][50];
    20 int dep[maxn];
    21 inline void dfs(int root){
    22     for(int i=0;i<to[root].size();i++){
    23         int y=to[root][i];
    24         if(y!=p[root][0]){
    25             dep[y]=dep[root]+1;
    26             p[y][0]=root;
    27             MAX[y][0]=cost[root][i];
    28             sum[y][0]=cost[root][i];
    29             for(int k=1;k<=30;k++){
    30                 int zu=1<<k;
    31                 if(zu<=dep[y]){
    32                     p[y][k]=p[p[y][k-1]][k-1];
    33                     MAX[y][k]=max(MAX[y][k-1],MAX[p[y][k-1]][k-1]);
    34                     sum[y][k]=sum[y][k-1]+sum[p[y][k-1]][k-1];
    35                 }
    36             }
    37             dfs(y);
    38         }
    39     }
    40 }
    41 inline void LCA(int x,int y){
    42     int ans1=0,ans2=0;
    43     if(dep[x]>dep[y]) swap(x,y);
    44     int delta=dep[y]-dep[x];
    45     for(int i=0;i<=30;i++){
    46         int h=1<<i; h=h&delta;
    47         if(h!=0){
    48             ans1+=sum[y][i]; ans2=max(ans2,MAX[y][i]);
    49             y=p[y][i];
    50         }
    51     }
    52     if(x==y){
    53         cout<<x<<" "<<ans1<<" "<<ans2<<endl;
    54         return ;
    55     }
    56     for(int i=30;i>=0;i--){
    57         if(p[y][i]!=p[x][i]){
    58             ans1+=sum[x][i]; ans1+=sum[y][i];
    59             ans2=max(ans2,MAX[x][i]); ans2=max(ans2,MAX[y][i]);
    60             x=p[x][i]; y=p[y][i];
    61         }
    62     }
    63     ans1+=sum[x][0]; ans1+=sum[y][0];
    64     ans2=max(ans2,MAX[x][0]); ans2=max(ans2,MAX[y][0]);
    65     cout<<p[x][0]<<" "<<ans1<<" "<<ans2<<endl; 
    66 }
    67 int main(){
    68     N=read(); M=read(); Q=read();
    69     for(int i=1;i<=M;i++){
    70         int u,v,c;
    71         u=read(); v=read(); c=read();
    72         to[u].push_back(v); to[v].push_back(u);
    73         cost[u].push_back(c); cost[v].push_back(c);
    74     }
    75     p[1][0]=-1; dep[1]=0;
    76     dfs(1);
    77     for(int i=1;i<=Q;i++){
    78         int u,v;
    79         u=read(); v=read();
    80         LCA(u,v);
    81     }
    82     return 0;
    83 }
  • 相关阅读:
    GitHub上传项目遇到的问题 安静点
    jQuery自定义动画 安静点
    WPF验证器 安静点
    jQuery自定义插件 安静点
    jQuery多库共存 安静点
    WPF之行为(Behavior) 安静点
    jQuery显示隐藏 安静点
    window.onload与 $(document).ready()区别 安静点
    jQuery展开收缩 安静点
    jQuery动态导航栏 安静点
  • 原文地址:https://www.cnblogs.com/CXCXCXC/p/4626591.html
Copyright © 2011-2022 走看看