这是一个菜鸡的博客|

Avarice_Zhao

园龄:5年8个月粉丝:1关注:9

倍增求LCA

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

题目描述

如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

输入格式

第一行包含三个正整数 N,M,S,分别表示树的结点个数、询问的个数和树根结点的序号。

接下来 N1 行每行包含两个正整数 x,y,表示 x 结点和 y 结点之间有一条直接连接的边(数据保证可以构成树)。

接下来 M 行每行包含两个正整数 a,b,表示询问 a 结点和 b 结点的最近公共祖先。

输出格式

输出包含 M 行,每行包含一个正整数,依次为每一个询问的结果。

样例 #1

样例输入 #1

5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5

样例输出 #1

4
4
1
4
4

提示

对于 30% 的数据,N10M10

对于 70% 的数据,N10000M10000

对于 100% 的数据,N500000M500000

样例说明:

该树结构如下:

第一次询问:2,4 的最近公共祖先,故为 4

第二次询问:3,2 的最近公共祖先,故为 4

第三次询问:3,5 的最近公共祖先,故为 1

第四次询问:1,2 的最近公共祖先,故为 4

第五次询问:4,5 的最近公共祖先,故为 4

故输出依次为 4,4,1,4,4

2021/10/4 数据更新 @fstqwq:应要求加了两组数据卡掉了暴力跳。

代码

// Problem: P3379 【模板】最近公共祖先(LCA)
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3379
// Memory Limit: 512 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
//fw
#include<bits/stdc++.h>
#define pii pair <int, int>
#define pll pair <ll, ll>
#define endl '\n'
#define il inline
#define pb push_back
#define fi first
#define se second
#define lc u<<1
#define rc u<<1|1
using namespace std;
typedef long long ll;
const int N=5e5+5,M=2*N;//开双向边
int h[N],e[M],ne[M],idx;//前向星
int fa[N][25],q[N];//fa[i][j]从i开始跳2^j步跳到的点
int n,m,root;
int depth[N];//每个点的深度,用于把a,b跳到同一层
void add(int a,int b)//前向星加边
{
e[idx]=b;
ne[idx]=h[a];
h[a]=idx++;
}
void bfs()
{
memset(depth,0x3f,sizeof depth);//深度初始化
depth[0]=0;depth[root]=1;//定义0号点为哨兵,防止跳过头
q[0]=root;
int hh=0,tt=0;
while(hh<=tt)//宽搜计算深度
{
int t=q[hh++];
for(int i=h[t];~i;i=ne[i])
{
int j=e[i];
if(depth[j]>depth[t]+1)
{
depth[j]=depth[t]+1;
q[++tt]=j;
fa[j][0]=t;//倍增求fa,与st表类似
for(int k=1;k<=20;k++)
{
fa[j][k]=fa[fa[j][k-1]][k-1];
}
}
}
}
}
int lca(int a,int b)
{
if(depth[a]<depth[b])swap(a,b);//用a表示较深的点
for(int k=20;k>=0;k--)//把a和b跳到同一层
{
if(depth[fa[a][k]]>=depth[b])
a=fa[a][k];
}
if(a==b)return a;//如果跳到同一层后相等,则说明这个点就是最近公共祖先
for(int k=20;k>=0;k--)//如果不相等则,两个点一起往上跳
{
if(fa[a][k]!=fa[b][k])//如果跳过头或者两个点的父节点是一个点则不跳
{
a=fa[a][k];
b=fa[b][k];
}
}
return fa[a][0];//返回父节点即lca
}
int main()
{
memset(h,-1,sizeof h);//前向星初始化
cin>>n>>m>>root;
for(int i=1;i<=n-1;i++)
{
int a,b;
cin>>a>>b;
add(a,b),add(b,a);
}
bfs();//预处理出depth和fa
while(m--)//处理每组询问
{
int a,b;
cin>>a>>b;
cout<<lca(a,b)<<endl;
}
return 0;
}

本文作者:Avarice_Zhao

本文链接:https://www.cnblogs.com/avarice/p/16418818.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Avarice_Zhao  阅读(10)  评论(0编辑  收藏  举报
评论
收藏
关注
推荐
深色
回顶
收起
点击右上角即可分享
微信分享提示