D09 倍增算法 P3379【模板】最近公共祖先(LCA)

视频链接:321 倍增算法 P3379【模板】最近公共祖先(LCA)_哔哩哔哩_bilibili

 

 

 

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

// 2.6s
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

const int N=500005;
int n,m,s;
vector<int> e[N];
int dep[N],fa[N][22];

void dfs(int x,int f){ //树增dep,fa
  dep[x]=dep[f]+1; fa[x][0]=f;
  //x上面2,4,8...的祖先fa
  for(int i=1; i<=20; i++) 
    fa[x][i]=fa[fa[x][i-1]][i-1]; 
  for(int y : e[x])
    if(y!=f) dfs(y,x);
}
int lca(int x,int y){ //树增lca
  if(dep[x]<dep[y]) swap(x,y);
  //x先大步后小步向上跳,直到与y同层
  for(int i=20; ~i; i--)
    if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
  if(x==y) return y;
  //x,y一起向上跳,直到lca的下面
  for(int i=20; ~i; i--)
    if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
  return fa[x][0];
}
int main(){
  scanf("%d%d%d",&n,&m,&s); int a,b;
  for(int i=1; i<n; i++){
    scanf("%d%d",&a,&b);
    e[a].push_back(b); e[b].push_back(a);
  }
  dfs(s,0);
  while(m--)
    scanf("%d%d",&a,&b),printf("%d\n",lca(a,b));
}

 

// 2.0s
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=5e5+10,M=2*N; 
int n,m,s,a,b;
int dep[N],fa[N][22];
int h[N],to[M],ne[M],tot;
void add(int a, int b){
  to[++tot]=b,ne[tot]=h[a],h[a]=tot;
}
void dfs(int x, int f){
  dep[x]=dep[f]+1; fa[x][0]=f;
  for(int i=0; i<=20; i++) 
    fa[x][i+1]=fa[fa[x][i]][i];
  for(int i=h[x]; i; i=ne[i])
    if(to[i]!=f) dfs(to[i], x);
}
int lca(int x, int y){
  if(dep[x]<dep[y]) swap(x, y);
  for(int i=20; ~i; i--)
    if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
  if(x==y) return y;
  
  for(int i=20; ~i; i--)
    if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
  return fa[x][0];
}
int main(){
  scanf("%d%d%d", &n,&m,&s);
  for(int i=1; i<n; i++){
    scanf("%d%d",&a,&b);
    add(a,b); add(b,a);
  }
  dfs(s, 0);
  while(m--){
    scanf("%d%d", &a, &b);
    printf("%d\n",lca(a, b));
  }
  return 0;
}

 

posted @ 2022-05-28 13:23  董晓  阅读(2804)  评论(0编辑  收藏  举报