LCA倍增求解

可能是人生的第一篇博客?竟然被我拿来记代码了。。

题源:https://www.luogu.com.cn/problem/P3379

没开2倍跳过非法范围WA了三次,希望以后回来看还能看懂

#include <iostream>
#include <stdio.h>
#include <cstring>
#define maxn 500005
using namespace std;
struct Edge
{
    int next, to;
} edge[maxn * 2]; //开双倍前向星,存储两个相反有向边(无法确定父子关系)
int head[maxn], dep[maxn], f[maxn][31], num = 0; //head意为以该下标为起点的边集中最后加入的在edge中对应的下标,f[n][i]意为n最近的第2^i个祖先编号
                                                 //num初始化为0,将0预留为dfs的假想起点
void add_edge(int u, int v)
{
    // 双向存储
    edge[++num].next = head[u]; edge[num].to = v; head[u] = num; //注意前一个head[u]和后一个head[u]的区别,前一个意为上一条边的编号,后一个更新为新加入的编号,注意顺序
    edge[++num].next = head[v]; edge[num].to = u; head[v] = num;
}
void dfs(int u, int fa)
{
    dep[u] = dep[fa] + 1;
    for (int i = 1; (1 << i) <= dep[u]; ++i)
    {
        f[u][i] = f[f[u][i - 1]][i - 1]; //2^i-1 + 2^i-1 = 2^i,递推预处理出树
    }
    for (int i = head[u]; i; i = edge[i].next)
    {
        int v = edge[i].to;
        if (v == fa) continue; //根据父子关系,排除另一条有向边
        f[v][0] = u;
        dfs(v, u);
    }
}
int lca(int x, int y)
{
    if (dep[x] < dep[y]) swap(x, y);
    //使x,y位于同一深度
    for (int i = 30; i >= 0; --i)
    {
        if (f[x][i] == 0) continue; //超出范围,即等于0要跳过
        if (dep[f[x][i]] >= dep[y]) x = f[x][i];
        if (x == y) return x;
    }
    for (int  i = 30; i >= 0; --i)
    {
        if (f[x][i] == 0 || f[y][i] == 0) continue; //同上
        if (f[x][i] != f[y][i]) //在lca以上的点都满足相等条件,因为lca的祖先也是x,y的祖先
        {
            x = f[x][i]; y = f[y][i];
        }
    }
    return f[x][0]; //由于二进制数的特性,每一位数只有01两种可能,从首位不断逼近下一位(中间过程是假使后尾全是0)直至个位可得到原数
}
int main()
{
    int n, m, s, x, y;
    memset(head, 0, sizeof(head));
    memset(dep, 0, sizeof(dep));
    memset(f, 0, sizeof(f)); //注意初始化为0
    scanf("%d%d%d", &n, &m, &s);
    for (int i = 1; i < n; ++i)
    {
        scanf("%d%d", &x, &y);
        add_edge(x, y);
    }
    dfs(s, 0); //辅助0
    for (int i = 0; i < m; ++i)
    {
        scanf("%d%d", &x, &y);
        printf("%d\n", lca(x, y));
    }
}

猜你喜欢

转载自www.cnblogs.com/jionkitten/p/12209174.html
今日推荐