最近公共祖先

Posted hrj1

tags:

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

【题目描述】:

有根树在计算机科学工程领域是一个人人熟知的数据结构类型。下面是一个例子。

8->(1,4,5);1->(13,14);4->(6,10);5->(9);6->(7,15);10->(2,11,16);16->(3,12);

在这个图中,每个点都是由1, 2,...,16中的某个数字标记的。8号点是树的根。如果x号点在y号点到根的路径上,则x是y的祖先。比如4是16的祖先,10也是。事实上,8,4,10,16都是16的祖先。记住,一个节点本身就是自己的祖先。再比如8,4,6,7是7的祖先。

如果x既是y的祖先也是z的祖先则称x是y和z公共祖先。也就是说8和4都是16和7的公共祖先。

如果x在y和z的所有公共祖先中距离y和z最近,则x是y和z的最近公共祖先。也就是说4是16和7的最近公共祖先而不是8,因为4比8更近。

再举一些例子:节点2和3的最近共同祖先是节点10,节点6和13的最近共同祖先是节点8,节点4和12的最近共同祖先是节点4。在最后一个例子中,如果Y是Z的祖先,那么Y和Z的最近共同祖先是Y。

编写一个程序,找出树中两个不同节点的最近共同祖先。

【输入描述】:

第一行,N和M表示节点数和询问数,节点编号1至N;

以下N-1行,每行两个整数a和b,表示a是b的父亲节点;

之后M行,每行两个不相同的数,表示询问它们的最近共同祖先。

【输出描述】:

M行,每行一个数表示对应的询问结果。

【样例输入】:

16 1
1 14
8 5
10 16
5 9
4 6
8 4
4 10
1 13
6 15
10 11
6 7
10 2
16 3
8 1
16 12
16 7

【样例输出】:

4

【时间限制、数据范围及描述】:

时间:1s 空间:256M

对于 40%的数据:1<=N,M<=3000

对于 100%的数据:1<=N,M<=2×10^5

 

#include<cstdio>
#include<iostream>
using namespace std;

const int Max=500005;

int n,m,x,y,cnt,list[Max],s[Max],d[Max],f[Max],hhh[Max];

int son[Max],c[Max];

struct xo 
    int to,next;
a[4*Max];

void add(int e,int r) 
    a[++cnt].to=r; 
    a[cnt].next=list[e];
    list[e]=cnt; 
 

inline int read()
    int s=0,w=1;
    char ch=getchar();
    while(ch<0||ch>9)
        if(ch==-)
            w=-1;
        
        ch=getchar();
    
    while(ch>=0&&ch<=9)
        s=s*10+ch-0;
        ch=getchar();
    
    return s*w;


void dfs1(int n,int kkksc03)
    s[n]=1;
    d[n]=d[kkksc03]+1;
    f[n]=kkksc03;
    int kkksc04;
    for(int i=list[n];i;i=a[i].next) 
        kkksc04=a[i].to;
        if(kkksc04!=kkksc03) 
            dfs1(kkksc04,n);
            s[n]+=s[kkksc04];
            if(!son[x]||s[son[n]]<s[kkksc04])
                son[n]=kkksc04;
            
        
    


void dfs2(int n,int kkksc03)
    c[n]=kkksc03;
    if(son[n])
        dfs2(son[n],kkksc03);
    
    else
        return;
    
    int kkksc04;
    for(int i=list[n];i;i=a[i].next) 
        kkksc04=a[i].to;
        if(kkksc04!=f[n]&&kkksc04!=son[n])
            dfs2(kkksc04,kkksc04);
        
    


int lca(int a,int b)
    while(c[a]!=c[b])
        if(d[c[a]]<d[c[b]])
            swap(a,b);
        
        a=f[c[a]];
    
    return d[a]<d[b]?a:b;


int main()
    int kkksc03;
    n=read();
    m=read();
    //kkksc03=read();
    for(int i=1;i<=n-1;i++)
        x=read();
        y=read();
        add(x,y);
        hhh[y]=x;
        add(y,x);
    
    for(int i=1;i<=n;i++)
        if(hhh[i]==0)
            kkksc03=i;
            break;
        
    
    dfs1(kkksc03,0);
    dfs2(kkksc03,kkksc03);
    while(m--)
        x=read();
        y=read();
        printf("%d\n",lca(x,y));
    
    return 0;

 

以上是关于最近公共祖先的主要内容,如果未能解决你的问题,请参考以下文章

LCA(最近公共祖先)——离线 Tarjan 算法

[转]LCA 最近公共祖先

求二叉搜索树的最近公共祖先(与那个普通二叉树最近公共祖先类似)

LeetCode二叉树的最近公共祖先

算法详解之最近公共祖先(LCA)

最近公共祖先(LCA)---tarjan算法