LCA(最近公共祖先)-倍增算法
例题啥的还不完善,等有机会再整理吧
/*少说话,多做事*/
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <sstream>
#include <map>
#include <set>
#include <queue>
#include <stdlib.h>
//#include<bits/stdc++.h>
//ios::sync_with_stdio(0);
//cin.tie(0);
//cout.tie(0);
typedef long long ll;
using namespace std;
/*
第一行:n (n头牛)(1-5e4) Q(询问次数)1-2e5
接下来n行:牛的高度(1-2e5)
接下来Q行 Q次询问
m行(m次询问)i j : 表示i与j之间的距离是多少
DFS+ST:将树看成一个无向图,u和v的公共祖先一定在u和v之间的最短路径上,
(1)DFS:从树T的根开始,进行深度优先遍历(将树看成一个无向图),并记录好每次到达的顶点。
由于每条边恰好经历两次,所以一共记录了2n-1个点,用E[1~2n-1]来表示
(2)计算R:用R[i]表示E数组中第一个值为i的元素下标
如果R[u]<R[v],DFS访问的顺序是E[R[u],R[u]+1,....R[v]].
虽然其中包含u的后代,但深度最小的还是u与v的公共祖先
(3)RMQ:计算RMQ
当R[u]>=R[v]时,LCA[T,u,v]=RMQ(L,R[v],R[u])
否则: LCA[T,u,v]=RMQ(L,R[u],R[v])
*/
inline int read()
{
int f=1,x=0;
char c=getchar();
while(!isdigit(c)){if(c=='-')f*=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int N=5e5+5;
int a[N],n,m,s,to[N<<1],nxt[N<<1],grd[N][23],d[N],cnt;
int head[N];
void add(int x,int y)
{
to[++cnt]=y;
nxt[cnt]=head[x];
head[x]=cnt;//邻接表
}
void dfs(int x,int fa) //根节点 0
{
int i;
grd[x][0]=fa;//父节点(根节点x的父亲节点为0)
d[x]=d[fa]+1;//x节点的深度是他的父亲节点的深度+1
for(i=1;i<21;i++) //其实到本题19就可以了,习惯到20整一点哈哈哈
{
grd[x][i]=grd[grd[x][i-1]][i-1];//预处理grd数组
}
for(i=head[x];i;i=nxt[i]) //对x节点进行遍历
{
if(to[i]!=fa) dfs(to[i],x); //如果终点不是他的父亲节点,那么就进行更新
}
}
int lca(int x,int y)
{
int i;
if(d[x]<d[y]) //将x的深度调成更深的,然后将其跳到跟y一样深度
{
swap(x,y);
}
for(i=20;i>=0;i--) //从大到小枚举 (肯定可以跳到相同深度)
{
if(d[y]<=d[x]-(1<<i))//1<<i就是2^i,也可以预处理成数组
{
x=grd[x][i];
}
}
if(x==y) return x;//当y是x的祖先时
for(i=20;i>=0;i--)
{
if(grd[x][i]!=grd[y][i]) //如果不相等的话就往上跳,for循环结束后,可以确定再向上跳一次就是两者的父亲节点
{
x=grd[x][i];
y=grd[y][i];//一起往上跳
}
}
return grd[x][0]; //返回父节点 (就是再向上跳一次就是父亲节点)
}
/*邻接表 + 预处理grd数组 + 跳到相同深度 + 一起往上跳*/
int main()
{
n=read();m=read();s=read(); //树的节点个数 、 询问的个数 和 树根节点的序号
int i,j,x,y;
for(i=1;i<n;i++)
{
x=read();y=read();
add(x,y);
add(y,x);//邻接表(也是跟链式向前星)
}
dfs(s,0);//预处理
for(i=1;i<=m;i++)
{
x=read();y=read();
printf("%d\n",lca(x,y));
}
return 0;
}



上海得物信息集团有限公司公司福利 1166人发布