用“倍增法”求最近公共祖先(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δ 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 }