倍增LCA

  其实这个问题蒟蒻感觉,就是模拟,只不过,在模拟之前需要一些预处理。

  先谈谈倍增,其实就是对于寻找公共祖先,如果深度差距太大,就需要进行很多没有必要的计算:比如要跳4步,一步一步跳要4次,而我四步四步跳只要一次(当然有人人为我这么说太凑巧了,这里只是为了说明问题,并不是真实情况),那如果数据再大一点呢?倍增就显现出优势啦~。

  预处理:

  定义f[x][y]为从x->y需要跳2^y步,那么自然有f[x][y+1]=f [ f [ x ] [ y ] ] [ y ]。而且维护dep[]数组和f数组(f[v][0]=u)。

void Deal_first(int u,int fa)
{
    dep[u]=dep[fa]+1;
    for(int i=0; i<=19; i++)
        f[u][i+1]=f[f[u][i]][i];
    for(int j=head[u]; j; j=nxt[j])
    {
        int v=to[j];
        if(v==fa)
            continue;
        f[v][0]=u;
        Deal_first(v,u);
    }
}

  利用链式前向星,一直搜下去,并维护dep(别忘了我们之后是要改变深度的啊)。

  LCA本体:(简单易懂,就不解释了)

int LCA(int x,int y)
{
    if(dep[x]<dep[y])
        swap(x,y);
    for(int i=20; i>=0; i--)
    {
        if(dep[f[x][i]]>=dep[y])
            x=f[x][i];
        if(x==y)//如果x,y在同一个分支上,直接返回就好
            return x;
    }
    for(int i=20; i>=0; i--)
    {
        if(f[x][i]!=f[y][i])
        {
            x=f[x][i];
            y=f[y][i];
        }
        
    }
    return f[x][0];
}

  最后是完整代码:

#include<cstdio>
#include<iostream>
using namespace std;
#define maxn 500005
int n,m,s;
int to[2*maxn],head[2*maxn],nxt[2*maxn],cnt;
int dep[maxn],f[maxn][21];
void add(int a,int b)
{
    cnt++;
    to[cnt]=b;
    nxt[cnt]=head[a];
    head[a]=cnt;
}
void Deal_first(int u,int fa)
{
    dep[u]=dep[fa]+1;
    for(int i=0; i<=19; i++)
        f[u][i+1]=f[f[u][i]][i];
    for(int j=head[u]; j; j=nxt[j])
    {
        int v=to[j];
        if(v==fa)
            continue;
        f[v][0]=u;
        Deal_first(v,u);
    }
}
int LCA(int x,int y)
{
    if(dep[x]<dep[y])
        swap(x,y);
    for(int i=20; i>=0; i--)
    {
        if(dep[f[x][i]]>=dep[y])
            x=f[x][i];
        if(x==y)//如果x,y在同一个分支上,直接返回就好
            return x;
    }
    for(int i=20; i>=0; i--)
    {
        if(f[x][i]!=f[y][i])
        {
            x=f[x][i];
            y=f[y][i];
        }
        
    }
    return f[x][0];
}
int main()
{
    scanf("%d%d%d",&n,&m,&s);
    int a,b;
    for(int i=1; i<n; i++)
    {
        scanf("%d%d",&a,&b);
        add(a,b);
        add(b,a);
    }
    Deal_first(s,0);
    for(int i=1; i<=m; i++)
    {
        scanf("%d%d",&a,&b);
        int ans=LCA(a,b);
        printf("%d\n",ans);
    }
    return 0;
}

 


  

posted @ 2018-11-26 19:28  paopo  阅读(189)  评论(0编辑  收藏  举报