ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

LCA 返回最近公共祖先:预处理

2022-07-25 15:05:17  阅读:194  来源: 互联网

标签:fa 祖先 预处理 int depth LCA root 节点


三种祖先关系 a是b祖先 b是a祖先 a和b不是祖先关系

必备:知道根节点 必须存下来

有可能跳过根节点
int depth[N],f[][N];//N为(log节点数)+1
int q[N];

从根节点开始预处理;
需要设置0号点为哨兵
询问 p=lca(a,b)

向上标记法on:从一个点向根节点遍历标记公共祖先 ,然后另一个点也向上走 走到第一个标记过的位置 就是祖先

倍增法ologn 预处理nlogn 查询logn:f[i][j]从i开始 向上走2^j次方 走到的节点

f[i][0]i点向上走一步走到的节点 f[i][1]向上走两步走到的节点 f[i][2]向上走四步发现不存在值为空集
当j>0 f[i][j]=f[i][j-1]基础上2^j-1步
depth表示深度从上往下看的 根节点深度是1 i表示i节点的深度
于是lca
哨兵:如果f[i][j]跳过根节点那么设为0 0节点的深度为0
第一步让两个点跳到同一层: t=相差depth(x)-depth(y)层 根据t的二进制跳 如果跳了不在y的上面那就跳:depth(f(x,k))>depth(y) 所以挑了之后就还能跳
第二步让两个点同时往上跳,直到跳到最近公共祖先的下一层:此时最近公共祖先为f[i][0]

祖孙查询https://www.acwing.com/activity/content/problem/content/1537/

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 40010,M=2*N;

int n,m;
int h[N], e[M], ne[M], idx;
int depth[N],fa[N][16];
int q[N];
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void bfs(int root){//从上到下
    memset(depth,0x3f , sizeof depth);
    depth[0]=0,depth[root]=1;//0号哨兵点深度为0,根节点深度为1
    int hh=0,tt=0;//bfs队列
    q[0]=root;
    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){//既然连了边,又比+1大说明是前面设置0正无穷的缘故
                depth[j]=depth[t]+1;
                q[++tt]=j;
                fa[j][0]=t;
                for (int k = 1; k <= 15; k ++ ){//因为fa初始化是0所以只要走不上求自动为0
                    fa[j][k]=fa[fa[j][k-1]][k-1];//j点在上面第k-1的祖先往上走k-1步
                }
            }
        }
    }
}
int lca(int a,int b){//两个fork从大到小实现 
    if(depth[a]<depth[b]) swap(a,b);//要求a在b的下面 不满足就换
    for (int k = 15; k >=0; k -- ){//从大到小开始走
        if(depth[fa[a][k]]>=depth[b])
            a=fa[a][k];
    }
    if(a==b) return a;
    for (int k = 15; k >=0; k -- ){
        if(fa[a][k]!=fa[b][k]){//说明不在公共祖先上 一起跳
            a=fa[a][k];
            b=fa[b][k];
        }
    }
    return fa[a][0];//向上走一步
}
int main()
{
    cin >> n;
    int root=0;
    memset(h, -1, sizeof h);
    for (int i = 0; i < n; i ++ ){
        int a,b;
        cin >> a>>b;
        if(b==-1) root=a;
        else add(a,b),add(b,a);
    }
    
    bfs(root);//预处理
    cin >> m;   
    while (m -- ){
        int a,b;cin>>a>>b;
        int p=lca(a,b);
        if(p==a) cout << 1<<endl;
        else if(p==b) cout << 2<<endl;
        else cout << 0<<endl;
    }
    return 0;
}

标签:fa,祖先,预处理,int,depth,LCA,root,节点
来源: https://www.cnblogs.com/liang302/p/16517340.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有