LCA的两种写法

第一种是离线的Tarjan算法

#include<cstdio>
using namespace std;
int rd(){
    int x=0,fl=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-'){fl=-1;}ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return fl*x;
}
int n,m,s,x,y,num1,num2;
int f[500001],dis[500001],a[500001][3],hd1[500001],hd2[500001];
bool vis[500001];
struct star{int nt,to,ds;}e[1000001],e2[1000001];
void add1(int from,int to){
    e[++num1].nt=hd1[from];
    e[num1].to=to;
    hd1[from]=num1;
}
void add2(int from,int to,int ds){
    e2[++num2].nt=hd2[from];
    e2[num2].to=to;
    e2[num2].ds=ds;
    hd2[from]=num2;
}
int find(int x){
    if(f[x]!=x)
        f[x]=find(f[x]);
    return f[x];
}
void un(int x,int y){
    int ra=find(x),rb=find(y);
    f[ra]=rb;
}
void tarjan(int x){
    vis[x]=1;
    for(int i=hd2[x];i;i=e2[i].nt){
        int to=e2[i].to,dis=e2[i].ds;
        if(vis[to]) 
            a[dis][2]=find(to);
    }
    for(int i=hd1[x];i;i=e[i].nt){
        int to=e[i].to;
        if(!vis[to]){
            tarjan(to);
            un(to,x);
        }
    }
}
int main(){
    n=rd();m=rd();s=rd();
    for(int i=1;i<n;i++){
        x=rd();y=rd();
        add1(x,y);add1(y,x);
    }
    for(int i=1;i<=m;i++){
        x=rd();y=rd();
        a[i][0]=x;a[i][1]=y;
        add2(x,y,i);add2(y,x,i);
    }
    for(int i=1;i<=n;i++)f[i]=i;
    tarjan(s);
    for(int i=1;i<=m;i++)
        printf("%d
",a[i][2]);
    return 0;
}

这个代码跑的飞快但是不太好理解。。

还有一种用倍增的思想

#include<iostream>
#include<cstdio>
using namespace std;
int rd(){
    int x=0,fl=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-'){fl=-1;}ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return fl*x;
}
int n,m,x,y,s,num=0,hd[500100],dep[500100],f[500100][21];
struct star{int nt,to;}e[1000100];
void add(int fm,int to){e[++num].to=to;e[num].nt=hd[fm];hd[fm]=num;}
void dfs(int x,int fa){
    dep[x]=dep[fa]+1;
    for(int i=1;i<=20;i++)
        f[x][i]=f[f[x][i-1]][i-1];
    for(int i=hd[x];i;i=e[i].nt)
    {
        int to=e[i].to;
        if(to==fa)continue;
        f[to][0]=x;
        dfs(to,x);
    }
}
int lca(int u,int v){
    if(dep[u]<dep[v])swap(u,v);
    for(int i=20;i>=0;i--){
        if(dep[f[u][i]]>=dep[v])
            u=f[u][i];
        if(u==v)return u;
    }
    for(int i=20;i>=0;i--)
        if(f[u][i]!=f[v][i]){
            u=f[u][i];v=f[v][i];
        }
    return f[u][0];
}
void print(int x){
    if(x<0){putchar('-');x=-x;}
    if(x>9)print(x/10);
    putchar(x%10+'0');
}
int main(){
    n=rd();m=rd();s=rd();
    for(int i=1;i<n;i++){
        x=rd();y=rd();
        add(x,y);add(y,x);
    }
    dfs(s,0);
    for(int i=1;i<=m;i++){
        x=rd();y=rd();
        print(lca(x,y));
        putchar('
');
    }
    return 0;
}

emmm....这种比较好理解但是跑的有点慢...

如果不太懂...可以看这个/*                      */

其实还有一种bfs版的玄学算法也安利一下

/*                                                           */

原文地址:https://www.cnblogs.com/2017noipak/p/7783968.html