码迷,mamicode.com
首页 > 其他好文 > 详细

LCA(最近公共祖先)

时间:2017-09-10 17:36:51      阅读:213      评论:0      收藏:0      [点我收藏+]

标签:roo   div   style   lca   getc   bool   str   col   man   

三种方法:

1.树链剖分(在上一篇代码中已经讲解得很详细,不再一一赘述)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<climits>
#include<ctime>
#include<queue>
#include<vector>
#include<map>
#include<algorithm>
#include<iomanip>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
typedef long long LL;
inline int read(){
    int x=0;char ch=getchar();
    while(ch<0||ch>9)ch=getchar();
    while(ch>=0&&ch<=9){
        x=x*10+ch-0;
        ch=getchar();
    }
    return x;
}
const int M=500001;
int n,m,root,cnt=0,head[M],to[M<<1],next[M<<1],son[M],siz[M],top[M],dep[M],fa[M];
void Insert(int u,int v){
    to[cnt]=v;
    next[cnt]=head[u];
    head[u]=cnt++;
    to[cnt]=u;
    next[cnt]=head[v];
    head[v]=cnt++;
}
void dfs1(int u){
    siz[u]=1;
    for(int i=head[u];i!=-1;i=next[i]){
        int v=to[i];
        if(v!=fa[u]){
            fa[v]=u;
            dep[v]=dep[u]+1;
            dfs1(v);
            siz[u]+=siz[v];
            if(!son[u]||siz[son[u]]<siz[v])son[u]=v;
        }
    }
}
void dfs2(int u){
    if(son[u]){
        top[son[u]]=top[u];
        dfs2(son[u]);
    }
    for(int i=head[u];i!=-1;i=next[i]){
        int v=to[i];
        if(v!=fa[u]&&v!=son[u]){
            top[v]=v;
            dfs2(v);
        }
    }
}
int lca(int x,int y){
    while(1){
        int tx=top[x],ty=top[y];
        if(tx==ty)return (dep[x]<dep[y]?x:y);
        if(dep[tx]<dep[ty])y=fa[ty];else x=fa[tx];
    }
}
int main(){
    n=read();m=read();root=read();
    memset(head,-1,sizeof(head));
    rep(i,1,n-1){
        int x=read(),y=read();
        Insert(x,y);
    }
    dep[root]=1;
    dfs1(root);
    top[root]=root;
    dfs2(root);
    while(m--){
        int x=read(),y=read();
        printf("%d\n",lca(x,y));
    }
    return 0;
}

2.Tarjan(慎用!如果题目是按照树剖卡常数的话,则此算法会MLE(空间大小为树剖的两倍))

有个特别形象的讲解在这里:http://www.cnblogs.com/JVxie/p/4854719.html

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<vector>
#include<map>
#include<algorithm>
#include<climits>
#include<ctime>
#include<iomanip>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
inline int read(){
    int x=0;char ch=getchar();
    while(ch<0||ch>9)ch=getchar();
    while(ch>=0&&ch<=9){
        x=x*10+ch-0;
        ch=getchar();
    }
    return x;
}

const int M=500001;
int n,m,root;
bool vis[M]={0};
int cnt=0,tot=0,f[M],ans[M],to[M<<1],head[M],next[M],q[M<<1],nt[M<<1],h[M];
void insert_edge(int x,int y){
    to[cnt]=y;
    next[cnt]=head[x];
    head[x]=cnt++;
    to[cnt]=x;
    next[cnt]=head[y];
    head[y]=cnt++;
}
void insert_query(int x,int y){
    q[tot]=y;
    nt[tot]=h[x];
    h[x]=tot++;
    q[tot]=x;
    nt[tot]=h[y];
    h[y]=tot++;
}
int Find(int x){
    if(f[x]==x)return x;
    else return f[x]=Find(f[x]);
}
void dfs(int fa,int u){
    for(int i=head[u];i!=-1;i=next[i]){
        int v=to[i];
        if(v!=fa)dfs(u,v);
    }
    for(int i=h[u];i!=-1;i=nt[i]){
        int v=q[i];
        if(vis[v])ans[i/2+1]=Find(v);
    }
    vis[u]=1;
    f[u]=fa;
}
            
int main(){
    n=read();m=read();root=read();
    memset(head,-1,sizeof(head));
    memset(h,-1,sizeof(h));
    rep(i,1,n)f[i]=i;
    rep(i,1,n-1){
        int x=read(),y=read();
        insert_edge(x,y);
    }
    rep(i,1,m){
        int x=read(),y=read();
        insert_query(x,y);
    }
    dfs(root,root);
    rep(i,1,m)printf("%d\n",ans[i]);
    return 0;
}

 

LCA(最近公共祖先)

标签:roo   div   style   lca   getc   bool   str   col   man   

原文地址:http://www.cnblogs.com/let-dream-fly/p/7501323.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!