UOJ #226.最近公共祖先


【题目描述】:

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

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

Code:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
int n,m,x,y,cnt,list[500001],s[500001],d[500001],f[500001],hhh[500001];
int son[500001],c[500001];
struct xo {
    int to,next;
}a[4*500001];
void add(int e,int r){
    a[++cnt].to=r;
    a[cnt].next=list[e];
    list[e]=cnt;
}
void dfs1(int n,int fa){
    s[n]=1;
    d[n]=d[fa]+1;
    f[n]=fa;
    int tt;
    for(int i=list[n];i;i=a[i].next) {
        tt=a[i].to;
        if(tt!=fa) {
            dfs1(tt,n);
            s[n]+=s[tt];
            if(!son[x]||s[son[n]]<s[tt]){
                son[n]=tt;
            }
        }
    }
}
void dfs2(int n,int fa){
    c[n]=fa;
    if(son[n]){
        dfs2(son[n],fa);
    }
    else{
        return;
    }
    int tt;
    for(int i=list[n];i;i=a[i].next) {
        tt=a[i].to;
        if(tt!=f[n]&&tt!=son[n]){
            dfs2(tt,tt);
        }
    }
}
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 fa;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n-1;i++){
        scanf("%d%d",&x,&y);
        add(x,y);
        hhh[y]=x;
        add(y,x);
    }
    for(int i=1;i<=n;i++){
        if(hhh[i]==0){
            fa=i;
            break;
        }
    }
    dfs1(fa,0);
    dfs2(fa,fa);
    while(m--){
        scanf("%d%d",&x,&y);
        printf("%d\n",lca(x,y));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/ukcxrtjr/p/11231457.html

时间: 2024-10-21 09:39:21

UOJ #226.最近公共祖先的相关文章

【洛谷P3379】【模板】最近公共祖先(LCA)

题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入样例#1: 5 5 4 3 1 2 4 5

50、树中两个节点的公共祖先

详细的询问: 1.该树是二叉查找树? 最近公共祖先----二叉查找树:(http://www.lintcode.com/problem/lowest-common-ancestor/) 思路:利用左子树特点:左子树 < 根 <= 右,输入节点跟根节点比较,都小于,在左子树,都大约右子树,递归的去遍历:找到当前节点在两个输入大小之间,当前节点就是. 递归和非递归 public class Solution { public TreeNode lowestCommonAncestor(TreeNo

[最近公共祖先] POJ 3728 The merchant

The merchant Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 4556   Accepted: 1576 Description There are N cities in a country, and there is one and only one simple path between each pair of cities. A merchant has chosen some paths and w

lca最近公共祖先(st表)

大体思路 1.求出每个元素在树中的深度 2.用st表预处理的方法处理出f[i][j],f[i][j]表示元素i上方第2^j行对应的祖先是谁 3.将较深的点向上挪,直到两结点的深度相同 4.深度相同后,祖先可能就在上方,再走几步就到了,于是两个点同时向上移 具体的方法和代码贴在下面 ↓ 具体来看 1.求出每个元素在树中的深度 //求每个节点在树中的深度 void dfs(int pos,int pre)//pre是pos的父节点 { for(int i=0;i<v[pos].size;i++)//

LCA(最近公共祖先)--tarjan离线算法 hdu 2586

HDU 2586 How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 11320    Accepted Submission(s): 4119 Problem Description There are n houses in the village and some bidirectional roads c

最近公共祖先 LCA Tarjan算法

来自:http://www.cnblogs.com/ylfdrib/archive/2010/11/03/1867901.html 对于一棵有根树,就会有父亲结点,祖先结点,当然最近公共祖先就是这两个点所有的祖先结点中深度最大的一个结点. 0 | 1 /   \ 2      3 比如说在这里,如果0为根的话,那么1是2和3的父亲结点,0是1的父亲结点,0和1都是2和3的公共祖先结点,但是1才是最近的公共祖先结点,或者说1是2和3的所有祖先结点中距离根结点最远的祖先结点. 在求解最近公共祖先为问

最近公共祖先

0. 概要 最近公共祖先,指的是在一颗有根树上,两个点的公共祖先中,深度最大的那个. 最直接的应用是求无权树上两个点的最短距离:$distance(u, v)  = depth(u) + depth(v) - 2depth(lca(u, v))$. 再有其他的应用则以后再提. 1 基于 dfs 序列上 RMQ 的稀疏表解法 首先 dfs 遍历树,如下如图中蓝色箭头的顺序.并记录: 1. 遍历点序列 $euler[] = \{1, 2, 1, 3, 5, 3, 6 ……$ 2. 每个点首次在 eu

LeetCode OJ:Lowest Common Ancestor of a Binary Tree(最近公共祖先)

Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w

最近公共祖先(三种算法)

最近研究了一下最近公共祖先算法,根据效率和实现方式不同可以分为基本算法.在线算法和离线算法.下面将结合hihocoder上的题目分别讲解这三种算法. 1.基本算法 对于最近公共祖先问题,最容易想到的算法就是从根开始遍历到两个查询的节点,然后记录下这两条路径,两条路径中距离根节点最远的节点就是所要求的公共祖先. 题目参见 #1062 : 最近公共祖先·一 附上AC代码,由于记录的方式采取的是儿子对应父亲,所以实现的时候有点小技巧,就是对第一个节点的路径进行标记,查找第二个节点的路径时一旦发现访问到