1. 程式人生 > >【模板】最近公共祖先(LCA)

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

href ret tar long long c++ amp 心算 class not

題目鏈接:https://www.luogu.org/problemnew/show/P3379

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define P pair<int,int>
const int N=5e5+10;
const int mod=1e9+7;
void
read(int &a) { a=0; int d=1; char ch; while(ch=getchar(),ch>9||ch<0) if(ch==-) d=-1; a=ch-0; while(ch=getchar(),ch>=0&&ch<=9) a=a*10+ch-0; a*=d; } void write(int x) { if(x<0) putchar(
45),x=-x; if(x>9) write(x/10); putchar(x%10+0); } int fa[N][20],head[N],num,dep[N],t; bool vis[N]; struct note { int to,next; }edge[2*N]; void add(int u,int v) { edge[++num].next=head[u]; edge[num].to=v; head[u]=num; } void dfs(int u,int h) { dep[u]
=h; for(re int i=1;i<=t;i++) { if((1<<i)>=h) break; fa[u][i]=fa[fa[u][i-1]][i-1];///倍增核心算法 } for(re int i=head[u];i;i=edge[i].next) { if(!vis[edge[i].to]) { vis[edge[i].to]=1; fa[edge[i].to][0]=u; dfs(edge[i].to,h+1); } } } int LCA(int a,int b) { if(dep[a]<dep[b]) swap(a,b); int d=dep[a]-dep[b]; for(re int i=0;i<=t;i++) if((1<<i)&d)///跑去d有1的位置,可以避免減多而導致的回溯 a=fa[a][i];///跳去跟B同樣的深度 if(a==b) return b; for(re int i=t;i>=0;i--) { if(!dep[fa[a][i]]) continue; if(fa[a][i]==fa[b][i]) continue; else a=fa[a][i],b=fa[b][i]; } return fa[a][0]; } int main() { int n,m,k; read(n); read(m); read(k); t=1.0*log2(n)+0.5;///算優化常數 for(re int i=0;i<n-1;i++) { int a,b; read(a); read(b); add(a,b); add(b,a); } vis[k]=1; fa[k][0]=k; dfs(k,1); while(m--) { int a,b; read(a); read(b); write(LCA(a,b)); putchar(\n); } return 0; }

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