D09 倍增算法 P3379【模板】最近公共祖先(LCA)
视频链接:321 倍增算法 P3379【模板】最近公共祖先(LCA)_哔哩哔哩_bilibili
// 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; }