zoukankan      html  css  js  c++  java
  • 【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的一道题,但我们这次用树链剖分的方法做。是一道树链剖分模板T~

    #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;
    }
  • 相关阅读:
    +1和*2
    线段树(区间最大值和最大值的个数)
    CodeForces
    莫队算法入门(暴力而不失优雅)
    二分迷宫
    全错排公式
    C++ PAT乙 1051. 复数乘法 (15)
    C++ PAT乙 1070. 结绳(25)
    C++ PAT乙 1080. MOOC期终成绩 (25)
    C++ PAT 1073. 多选题常见计分法(20)
  • 原文地址:https://www.cnblogs.com/wuhu-JJJ/p/13511490.html
Copyright © 2011-2022 走看看