https://www.luogu.org/problemnew/solution/P3379
LCA叫做最短公共祖先,用来求距离树上两个节点最近的公共点;
常用倍增算法:
#include<iostream> #include<cstdio> #include<vector> using namespace std; const int N=1E6+7; long long bits[30]; int depth[N],fa[N][30]; vector<int >ve[N]; //"---------预处理部分---------" void inint(){ bits[0]=1; for(int i=1;i<30;i++) bits[i]=bits[i-1]<<1;//用一个数组记录2的i次幂,每次向上爬满足条件的2的最大i次幂 } void dfs(int x,int y){//x为子节点,y为父节点 depth[x]=depth[y]+1;//子节点与父节点的关系 fa[x][0]=y; //"----核心之一 --" for(int i=1;i<30;i++) fa[x][i]=fa[fa[x][i-1]][i-1]; //"-------"每次向上爬2的i次幂相当于先爬2的i-1次幂,在爬2的i-1次幂 for(int i=0;i<ve[x].size();i++){//临接表存图与x相联的点出了子节点就是父节点。将父节点排除掉 int x1=ve[x][i]; if(x1!=y){ dfs(x1,x);//让x做父节点,x1做子节点 } } } //"-----------------------------------" int lca(int x,int y){//我们规定x为较深的点,y为较浅的一个点 if(depth[x]<depth[y]) swap(x,y);//如果说depth[x]小的话,,要交换一下; int dif=depth[x]-depth[y]; for(int i=29;i>=0;i--){ if(dif>=bits[i]){//将X和y变成同一高度。因就相当于将dif用二进制划分,然后记录一下x此时的位置 x=fa[x][i]; dif=dif-bits[i]; } } if(x==y) return x;//如果二者相等了说明二者在树枝的同一侧,y就是x的最近的根 for(int i=29;i>=0;i--){ if(depth[x]>=bits[i]&&fa[x][i]!=fa[y][i]){//找到x和y的根的第一子节点 x=fa[x][i]; y=fa[y][i]; } } return fa[x][0];//返回自已子节点的父节点,就是公共根了 } int main(){ inint(); int n,m,s; scanf("%d%d%d",&n,&m,&s); int x,y; for(int i=1;i<=n-1;i++){ scanf("%d%d",&x,&y); ve[x].push_back(y); ve[y].push_back(x); } dfs(s,0);//在这里s是总的根节点,我们规定如果越界,记为0,比如s的父节点就越界了,记录为0; for(int i=1;i<=m;i++){ scanf("%d%d",&x,&y); printf("%d\n",lca(x,y)); } return 0; }