【模板】最近公共祖先(LCA)(倍增做法)
题目描述
如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。
输入格式
第一行包含三个正整数 N,M,S,分别表示树的结点个数、询问的个数和树根结点的序号。
接下来 N−1 行每行包含两个正整数 x,y,表示 x 结点和 y 结点之间有一条直接连接的边(数据保证可以构成树)。
接下来 M 行每行包含两个正整数 a,b,表示询问 a 结点和 b 结点的最近公共祖先。
输出格式
输出包含 M 行,每行包含一个正整数,依次为每一个询问的结果。
说明/提示
对于 30% 的数据,N≤10,M≤10。
对于 70% 的数据,N≤10000,M≤10000。
对于 100% 的数据,N≤500000,M≤500000。
模板题LCA 指路查看网页第一篇题解
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define INF 0x3f3f3f3f using namespace std; int N=0,n,m,s,dep[600001],lg[600001],last[5000001],f[600001][51]; struct node{ int next,to; }a[5000001]; void add(int UU,int VV){ a[++N].to=VV; a[N].next=last[UU]; last[UU]=N; } void dfs(int me,int father){//预处理 f[me][0]=father; dep[me]=dep[father]+1; for(int i=1;i<=lg[dep[me]];i++) f[me][i]=f[f[me][i-1]][i-1];///意思是now的2^i祖先等于now的2^(i-1)祖先的2^(i-1)祖先 //2^i = 2^(i-1) + 2^(i-1) for(int i=last[me];i;i=a[i].next) if(a[i].to!=father) dfs(a[i].to,me); } int LCA(int x,int y){ if(dep[x]<dep[y]) swap(x,y); while(dep[x]>dep[y]) x=f[x][lg[dep[x]-dep[y]]-1]; if(x==y) return x; for(int i=lg[dep[x]]-1;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } int main(){ scanf("%d%d%d",&n,&m,&s); for(int i=1;i<=n-1;i++){ int X,Y; scanf("%d%d",&X,&Y); add(X,Y); add(Y,X); } for(int i=1;i<=n;i++) lg[i]=lg[i-1]+(1<<lg[i-1]==i); dfs(s,0); while(m--){ int A,B; scanf("%d%d",&A,&B); printf("%d\n",LCA(A,B)); } }

浙公网安备 33010602011771号