• 【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

    题解;Lca题目 为了练习用tarjan做了~

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<bits/stdc++.h>
    typedef long long ll;
    using namespace std;
    const int N=500002;
    int yc,n,x,y,m,cnt,head[N];
    struct node{
        int to;
        int next;
    }e[N];
    void add(int a,int b){
        e[++cnt].to=b;
        e[cnt].next=head[a];
        head[a]=cnt;
    }
    int ta[N],ti[N],son[N],sz[N],dep[N],fa[N],dfsc,top[N];
    
    void dfs1(int u,int pa,int de){
        son[u]=0; sz[u]=1; dep[u]=de; fa[u]=pa;
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to;
            if(v==pa) continue;
            dfs1(v,u,de+1);
            sz[u]+=sz[v];
            if(sz[v]>sz[son[u]]) son[u]=v;
        }
    }
    
    void dfs2(int u,int pa){
        ti[u]=++dfsc; 
        top[u]=pa;
        if(son[u]!=0) dfs2(son[u],pa);
        //else return;
        for(int i=head[u];i;i=e[i].next)
            if(e[i].to!=son[u] && e[i].to!=fa[u]) 
               dfs2(e[i].to,e[i].to);
    }
    
    int lca(int x,int y){
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            x=fa[top[x]];
        }
        if(dep[x]>dep[y]) swap(x,y);
        return x;
    }
    int main(){
        scanf("%d %d",&n,&m);
        for(int i=1;i<n;i++) 
           { scanf("%d %d",&x,&y); add(x,y); add(y,x); ta[y]=x; }
        for(int i=1;i<=n;i++)
            if(ta[i]==0) { yc=i; break; }
        dfs1(yc,yc,0); dfs2(yc,yc);
        for(int i=1;i<=m;i++)
           { scanf("%d %d",&x,&y); printf("%d
    ",lca(x,y)); }
        return 0;
    }
  • 相关阅读:
    ubuntu 安装 redis desktop manager
    ubuntu 升级内核
    Ubuntu 内核升级,导致无法正常启动
    spring mvc 上传文件,但是接收到文件后发现文件变大,且文件打不开(multipartfile)
    angular5 open modal
    POJ 1426 Find the Multiple(二维DP)
    POJ 3093 Margritas
    POJ 3260 The Fewest Coins
    POJ 1837 Balance(二维DP)
    POJ 1337 A Lazy Worker
  • 原文地址:https://www.cnblogs.com/wuhu-JJJ/p/13539922.html
Copyright © 2020-2023  润新知