c++最近公共祖先LCA(倍增算法和tarjan)

1.倍增

找两个点的LCA,先让它们深度相同,然后倍增向上跳跃,跳到使他们的值不相同的最浅层的点,那么此点的上方即是LCA。

#include
#include
#include
#include
#include
#include
#include
#define in(x) scanf("%d",&x);
using namespace std;
int n,m,rt,d[500007],fa[500007][22];
int heade[1000007],nexte[1000007],cnt=0,to[1000007];
void build_tree(int x,int father)
{
    int k=log(d[x])/log(2);
    for(int j=1;j<=19;++j)
    fa[x][j]=fa[fa[x][j-1]][j-1];
    for(int i=heade[x];i;i=nexte[i])
    {
        int u=to[i];
        if(u!=father)
        {
            d[u]=d[x]+1;
            fa[u][0]=x;
            build_tree(u,x);
        }
    }
}
inline int read()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') w=-1;ch=getchar();
    }
    while(ch>='0'&&ch<='9') 
    {
        x=(x<<3)+(x<<1)+ch-'0';ch=getchar();
    }
    return x*w;
}
int find_lca(int l,int r)
{
    if(d[l]>d[r]) swap(l,r);//l=4,r=2
    int k=log(d[r]-d[l]+1)/log(2);
    for(int i=0;i<=k+1;++i)
    {
        if((1<=0;--i)
    {
        if(fa[l][i]==fa[r][i]) continue;
        l=fa[l][i];r=fa[r][i];
    }
    return fa[l][0];
}
int main()
{
    n=read();m=read();rt=read();
    for(int i=1;i<=n-1;++i)
    {
        int x,y;x=read();y=read();
        nexte[++cnt]=heade[x];heade[x]=cnt;to[cnt]=y;
        nexte[++cnt]=heade[y];heade[y]=cnt;to[cnt]=x;
    }
    d[rt]=1;fa[rt][0]=0;
    build_tree(rt,-1);
    for(int i=1;i<=m;++i)
    {
        int x,y;x=read();y=read();
        printf("%d\n",find_lca(x,y));
    }
    return 0;
}
2.tarjan算法

离线算法,将所求先储存,然后结合并查集深搜点,如果所求的两个点都vis[]==1那么输出他们的father。

不理解就画一下图模拟一下。

#include
#include
#include
#include
#include 
#include
using namespace std;
int n,m,rt;
int to[1000009],head[1000009],nxt[1000009],cnt=0,cnt1=0,ans[500009],fa[500009];
int to1[1000009],head1[1000009],nxt1[1000009],mark[1000009];bool vis[500009];
inline int read()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') w=1;ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<3)+(x<<1)+ch-'0';ch=getchar();
    }
    return x*w;
} 
int find(int x)
{
    if(fa[x]==x) return x;
    else return fa[x]=find(fa[x]);
}
void onion(int a,int b)
{
    int x=find(a),y=find(b);
    if(x==y) return ;
    else fa[x]=y;
}
void find_lca(int x,int fa)
{    
    for(int i=head[x];i;i=nxt[i])
    if(to[i]!=fa)
    find_lca(to[i],x);
    vis[x]=1;
    for(int i=head1[x];i;i=nxt1[i])
    if(vis[to1[i]]==1)
    ans[mark[i]]=find(to1[i]);
    if(fa!=-1) onion(x,fa);
}
int main()
{
     n=read();m=read();rt=read();
     for(int i=1;i<=n;++i)
     fa[i]=i;
     for(int i=1;i<=n-1;++i)
     {
         int x,y;x=read();y=read();
         nxt[++cnt]=head[x];head[x]=cnt;to[cnt]=y;
         nxt[++cnt]=head[y];head[y]=cnt;to[cnt]=x;
     }
     for(int i=1;i<=m;++i)
     {
         int x,y;x=read();y=read();
         nxt1[++cnt1]=head1[x];head1[x]=cnt1;to1[cnt1]=y;mark[cnt1]=i;
         nxt1[++cnt1]=head1[y];head1[y]=cnt1;to1[cnt1]=x;mark[cnt1]=i;
     }
     find_lca(rt,-1);
     for(int i=1;i<=m;++i)
     printf("%d\n",ans[i]);
     return 0;
}



你可能感兴趣的:(LCA)