倍增求LCA

Posted potatorain

tags:

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

  原本计划上个星期写这篇博客,但是被耽误了一周。今晚来填坑。首先来介绍最近公共祖先(LCA)的概念:最近公共祖先_百度百科。这里我们介绍利用倍增求LCA。

  先来了解一下倍增的思想:倍增简介_博客

  假设询问的两点为u、v,对于如何求最近公共祖先,倍增算法的思想是这样的:

  (1)预处理得到每个节点的二次祖先。

  (2)如果u、v不在同一深度,则将u、v移动到同一深度。

  (3)采用二分逼近的思想,将u、v的指针同步移动到最远的非公共祖先。

  (4)特判此时u == v是否成立,成立则输出结果。不成立则LCA为u或v的父亲节点。

  以洛谷P3379为例,代码如下:

  

#include <iostream>
#include <cstdio>
using namespace std;
const int DEEP = 20;
const int MAXN = 10001;

struct LINE {
    int p;
    int next;
};
struct TREE {
    int d;
    int f[DEEP];
};

LINE l[MAXN * 2];
TREE t[MAXN];
int h[MAXN];
int n, m, s;

void add(int x, int lID) {
    l[lID].next = h[x];
    h[x] = lID;
}

void dfs(int f, int now) {
    int k = h[now];
    t[now].f[0] = f;
    t[now].d = t[f].d + 1;
    while(k) {
        if(l[k].p != f) {
            dfs(now, l[k].p);
        }
        k = l[k].next;
    }
}

void clcF() {
    for(int i = 1; i < DEEP; i++) {
        for(int j = 0; j <= n; j++) {
            t[j].f[i] = t[t[j].f[i - 1]].f[i - 1];
        }
    }
}

void findLCA(int x, int y) {
    int tmp;
    int l;
    if(t[x].d > t[y].d) {
        tmp = x;
        x = y;
        y = tmp;
    }
    l = t[y].d - t[x].d;
    for (int i = DEEP - 1; i >= 0; i--) {
        if (l >= (1 << i)) {
            l -= (1 << i);
            y = t[y].f[i];
        }
    }
    for(int i = DEEP - 1; i >= 0; i--)
    {
        if(t[x].f[i] != t[y].f[i])
        {
            x = t[x].f[i];
            y = t[y].f[i];
        }
    }
    if(x == y)
    {
        printf("%d
", x);
    }else
    {
        printf("%d
", t[x].f[0]);
    }
}

int main() {
    int a, b;
    int x, y;
    scanf("%d %d %d", &n, &m, &s);
    for(int i = 1; i < n; i++) {
        scanf("%d %d", &a, &b);
        l[i* 2 - 1].p = b;
        add(a, i * 2 - 1);
        l[i* 2].p = a;
        add(b, i * 2);
    }
    t[0].f[0] = 0;
    t[0].d = 0;
    dfs(0, s);
    clcF();
    for(int i = 1; i <= m; i++) {
        scanf("%d %d", &x, &y);
        findLCA(x, y);
    }
    return 0;
}

 

 

  

  

以上是关于倍增求LCA的主要内容,如果未能解决你的问题,请参考以下文章

求LCA——倍增

代码源 Div1 - 105#451. Dis(倍增求LCA)

倍增求LCA

倍增求lca模板

倍增求LCA

倍增求LCA