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

 题目链接:

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

代码:

细节解释:

1.思想上,用到了倍增的思想,让寻找LCA变得更快。

2.注意 f 数组的定义,还有lg初始化的方式

3.最重要的一句代码:2^(i-1)级祖先的2^(n-1)祖先,就是当前的2^n级祖先(因为2^i = 2^(i-1) + 2^(i-1))

f[u][i] = f[f[u][i-1]][i-1];

 

#include <bits/stdc++.h>
using namespace std;
const int maxn = 500005;
int f[maxn][20]; //f[i][j]表示i的第2^j级祖先
int d[maxn]; //结点深度
int lg[maxn]; //预处理以二为底的对数
int n, m, s;
vector<int> g[maxn];

void dfs(int u, int fa){
    f[u][0] = fa, d[u] = d[fa]+1; //直接父节点,深度
    for(int i=1; i<=lg[d[u]]; i++) //记录倍增级数的祖先编号
        f[u][i] = f[f[u][i-1]][i-1];//重点:意思是now的2^i祖先等于now的2^(i-1)祖先的2^(i-1)祖先
                                    //2^i = 2^(i-1) + 2^(i-1)
    for(int v : g[u])
        if(v != fa) dfs(v, u);
}
int LCA(int x, int y){
    if(d[x] < d[y]) swap(x, y); //不妨假设x的深度 >= y的深度,即x位置比y低
    while(d[x] > d[y]) x = f[x][lg[d[x]-d[y]]]; //x位置倍增上升,直到和y齐平
                                                //由于lg是向下取整,这里会根据倍增级数逐步接近y的高度
    if(x == y) return y; //特殊情况,y正好是x的祖先
    for(int k=lg[d[x]]; k>=0; k--){
        //这步也是重点,倍增上升,直到刚好找到LCA的下面两个子节点,后面就不会再进入if语句中了
        if(f[x][k] != f[y][k]) {x=f[x][k]; y=f[y][k];}
    }
    return f[x][0];
}
int main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n >> m >> s;
    for(int i=1; i<=n-1; i++){
        int a, b; cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for(int i=2; i<=n; i++) lg[i] = lg[i>>1]+1; //lg数组预处理,和st数组模板中的一样
    dfs(s, 0);
    for(int i=1; i<=m; i++){
        int a, b; cin >> a >> b;
        cout << LCA(a, b) << '\n';
    }
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值