树,LCA,最近公共祖先,倍增

Posted codemaker-li

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树,LCA,最近公共祖先,倍增相关的知识,希望对你有一定的参考价值。

最近公共祖先,

树上倍增,LCA,

fa [ i ] [ j ] 表示 i 节点向上 2j 的祖先

很像dp,

k 属于 [ 1 , log ( n ) ] ,f [ x ][ k ] = f [ f [ x ] [ k-1 ]] [k-1]

算lca时,

先不妨设 d [ x ] >= d [ y ]

二进制拆分

尝试从x 向上走 k = 2log (n),~~,21,20,

检查到的点是否比 y 深

每次检查中,若是,x= f [ x ] [ k ]

若仍未相会, 即 f [ x ] [ k ] != f [ y ] [ k ]

令 x = f [ x ] [ k ], y = f [ y ] [ k ]

最后,若 x = y , lca ( x , y )=y

看看代码

#include <cstdio>
#include <iostream>
#include <string>
#include <bits/stdc++.h>

using namespace std;
#define MAXN 50010
int fa[MAXN][20];
//f[i][j]表示i的2^j的祖先 
int dep[MAXN];//深度 
int dis[MAXN];//到根节点距离 

struct edge{
    int v;
    int w;
    int nxt;
}e[MAXN*2];
int head[MAXN];
int T,n,m,cnt;
int t;//指数次幂 t=(log(n)/log(2))+1 

void add(int x,int y,int z) {
    e[++cnt].v=y;
    e[cnt].w=z;
    e[cnt].nxt=head[x];
    head[x]=cnt;
} 
queue<int> q;
void bfs() {
    //预处理 
    q.push(1);
    dep[1]=1;
    while (q.size()) {
        int x=q.front();
        q.pop();
        for (int i=head[x];i;i=e[i].nxt) {
            int y=e[i].v;
            if (dep[y]) continue;
            dep[y]=dep[x]+1;
            dis[y]=dis[x]+e[i].w;
            fa[y][0]=x;
            for (int j=1;j<=t;j++) {
                fa[y][j]=fa[fa[y][j-1]][j-1];
            }
            q.push(y);
        }
    } 
}

int lca(int x,int y) {
    if (dep[x]>dep[y]) swap(x,y);
    for (int i=t;i>=0;i--) {
        if (dep[fa[y][i]]>=dep[x]) {
            y=fa[y][i];
        } 
    }
    if (x==y) return x;
    for (int i=t;i>=0;i--) {
        if (fa[x][i]!=fa[y][i]) {
            x=fa[x][i];
            y=fa[y][i];
        }
    }
    return fa[x][0];
}

int main () {
    t=(int)(log(n)/log(2))+1;
    memset(head,0,sizeof(head));
    memset(dep,0,sizeof(dep));
    cnt=0;
    cin>>n>>m;
    for (int i=1,x,y,z;i<n;i++) {
        cin>>x>>y>>z;
        add(x,y,z);
        add(y,x,z);
    }
    bfs();
    for (int i=1,x,y,len;i<=m;i++) {
        //询问
        cin>>x>>y;
        cout<<lca(x,y)<<endl;
        len=dis[x]+dis[y]-2*dis[lca(x,y)];
        cout<<len<<endl;
    } 
    return 0;
}

/*
10 5
1 2 2
1 3 4
2 4 3
2 5 7
3 6 2
3 7 4
4 8 2
5 9 3
6 10 1
6 7
9 3
8 5
10 6
4 7
*/

 

OK啦

以上是关于树,LCA,最近公共祖先,倍增的主要内容,如果未能解决你的问题,请参考以下文章

最近公共祖先(LCA)(链式前向星+倍增法)

lca(最近公共祖先(在线)) 倍增法详解

倍增法求LCA

LCA倍增求LCA

LCA 最近公共祖先

倍增LCA