倍增——LCA

Posted chdy

tags:

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

今天终于把倍增的LCA搞懂了!尽管周测都没写,尽管lca其实很简单,但这也是进度君的往前一点点的快乐。

倍增的lca其实关键就在于二进制的二进制的拆分(显然是两次的拆分,很奇妙,懂二进制的自然不觉得什么)。把最关键的地方在这里列举一下吧:

1.f[fa][i]=f[f[fa][i-1]][i-1];类似于状态转移,i表示2^i可以表示fa的2的i次方的祖先所以当前的fa的2^i的祖先就是它2-1次方的祖先的2-1次方的祖先

想要理解为什么是这样,1+1=2;2+2=4;4+4=8;8+8=16;故2^i-1+2^i-1=2^i;到这里就可以理解了吧。

2.for(int i=t;i>=0;i--) 这里的t是t=(int)(log(n)/log(2))+1;的出来的n是最大的数目也就是log数,if(depth[f[y][i]]>=depth[x]) y=f[y][i];这里的是指假如当前的深度和x的深度比,能调到和x一样深就跳,这个代码完成了将y跳到x,二进制的拆分就是如此神奇!!!。(dalao勿喷蒟蒻没见过二进制拆分)

3.for(int i=t;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];这里的也就是x,y虽然到了同样的深度但是呢,公共祖先还是没有出来所以可以进行同时向上爬(我要一步一步向上爬)因为二进制的拆分所以最后都会达到距离最近公共祖先最近的子节点处,所以最后输出x的父亲节点就是x,y的公共子节点了,二进制的拆分就是如此神奇!!!。(dalao勿喷蒟蒻没见过二进制拆分)

这就是lca的具体之处认真思考其实都很简单(无奈作业太多)多思考啊。

代码:

技术分享图片
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<ctime>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<map>
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
    return x*f;
}
const int maxn=500001<<1;
const int maxx=500001;
int n,m,s,t;
int lin[maxn],nex[maxn],ver[maxn],len=0;
int depth[maxx],f[maxx][30];
void add(int x,int y)
{
    ver[++len]=y;
    nex[len]=lin[x];
    lin[x]=len;
}
void dfs(int fa,int fath)
{
    depth[fa]=depth[fath]+1;
    f[fa][0]=fath;
    for(int i=1;i<=t;i++)
        f[fa][i]=f[f[fa][i-1]][i-1];
    for(int i=lin[fa];i;i=nex[i])
        if(ver[i]!=fath)
            dfs(ver[i],fa);
}
int lca(int x,int y)
{
    if(depth[x]>depth[y])
        swap(x,y);
    for(int i=t;i>=0;i--)
        if(depth[f[y][i]]>=depth[x])
            y=f[y][i];
    if(x==y)
        return x;
    for(int i=t;i>=0;i--)
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();s=read();
    t=(int)(log(n)/log(2))+1;
    for(int i=1;i<n;i++)
    {
        int x,y;
        x=read();y=read();
        add(x,y);add(y,x);
        
    }
    dfs(s,0);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        x=read();y=read();
        printf("%d
",lca(x,y));
    }
    return 0;
}
View Code

高歌取醉欲自慰,起舞落日争光辉。

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

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

LCA 算法倍增

树上倍增求LCA

倍增法求LCA——在线

求LCA——倍增

倍增法求LCA