lca倍增模板

https://www.luogu.org/problem/P3379

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 1e6 + 7;
int head[maxn],to[maxn],nex[maxn],d[maxn],fa[maxn][20];//fa[i][j]代表i點的第2^j個祖先
int tot;

void add(int x,int y)
{
    to[++tot] = y;
    nex[tot] = head[x];
    head[x] = tot;
}

void dfs(int x)
{
    for(int i = head[x];i;i = nex[i])
    {
        int v = to[i];
        if(!d[v])
        {
            d[v] = d[x] + 1;
            fa[v][0] = x;
            dfs(v);
        }
    }
}

int lca(int x,int y)
{
    if(d[x] < d[y])swap(x,y);//保證x是最深的
    for(int i = 19;i >= 0;i--)
    {
        if(d[fa[x][i]] >= d[y])
            x = fa[x][i];//將x移到和y一樣的深度
    }
    
    if(x == y)//x移到y了,那說明x就是xy祖先
        return x;
    for(int i = 19;i >= 0;i--)
    {
        if(fa[x][i] != fa[y][i])
        {
            x = fa[x][i];
            y = fa[y][i];//x,y一起上移
        }
    }
    return fa[x][0];//此時x和y已經在同一個節點下了,返回x的父節點即可。
}

int main()
{
    int n,m,s;scanf("%d%d%d",&n,&m,&s);
    for(int i = 1;i < n;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    }
    d[s] = 1;fa[s][0] = 0;
    dfs(s);
    
    for(int i = 1;i <= 19;i++)
    {
        for(int j = 1;j <= n;j++)
        {
            fa[j][i] = fa[fa[j][i - 1]][i - 1];//j的2^i次方祖先等於j的2^i-1次方祖先的2^i-1次方祖先。
        }
    }
    for(int i = 1;i <= m;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        printf("%d\n",lca(x,y));
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章