用“倍增法”求最近公共祖先(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 }
原文地址:https://www.cnblogs.com/CXCXCXC/p/4626591.html