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


    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 1
    1 4
    2 4
    3 2
    3 5
    1 2
    4 5
    输出样例#1:
    4
    4
    1
    4
    4
    

    说明

    时空限制:1000ms,128M

    数据规模:

    对于30%的数据:N<=10,M<=10

    对于70%的数据:N<=10000,M<=10000

    对于100%的数据:N<=500000,M<=500000

    样例说明:

    该树结构如下:

    第一次询问:2、4的最近公共祖先,故为4。

    第二次询问:3、2的最近公共祖先,故为4。

    第三次询问:3、5的最近公共祖先,故为1。

    第四次询问:1、2的最近公共祖先,故为4。

    第五次询问:4、5的最近公共祖先,故为4。

    故输出依次为4、4、1、4、4。

     1 #include<iostream>
     2 #include<cstdio>
     3 
     4 using namespace std;
     5 
     6 const int N = 500100;
     7 
     8 int n,m,root,ans,cnt;
     9 int head[N];
    10 int deth[N];
    11 int f[N][30];
    12 bool vis[N];
    13 struct Edge{
    14     int to,nxt;
    15 }e[N<<1];
    16 
    17 int Read()
    18 {
    19     int x=0,f=1;
    20     char c=getchar();
    21     while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
    22     while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();}
    23     return x*f;
    24 }
    25 
    26 void add(int a,int b)
    27 {
    28     ++cnt;
    29     e[cnt].to = b;
    30     e[cnt].nxt = head[a];
    31     head[a] = cnt;
    32 }
    33 
    34 void dfs(int a)
    35 {
    36     vis[a] = true;
    37     for(int i=1;i<=20;i++)
    38     {
    39         if(deth[a] < (1<<i)) break;
    40         f[a][i] = f[f[a][i-1]][i-1];
    41     }
    42     for(int i=head[a];i;i=e[i].nxt)
    43     {
    44         int now = e[i].to;
    45         if(!vis[now])
    46         {
    47             deth[now] = deth[a]+1;
    48             f[now][0]=a;
    49             dfs(now);
    50         }
    51     }
    52 }
    53 
    54 int lca(int u,int v)
    55 {
    56     if(deth[u] < deth[v])swap(u,v);
    57     int d = deth[u] - deth[v];
    58     for (int i=0; i<25; i++)    //值得注意的是,这里需要从零枚举
    59     { 
    60         if ( (1<<i) & d)//一个判断,模拟一下就会很清晰
    61             u = f[u][i];
    62     }
    63     if (u==v) return u;    
    64     for (int i=25; i>=0; i--) 
    65     {
    66         if (f[u][i]!=f[v][i])     //跳2^j步不一样,就跳,否则不跳
    67         {
    68             u = f[u][i];
    69             v = f[v][i];
    70         }
    71     }
    72     u = f[u][0];        //上述过程做完,两点都在LCA下一层,所以走一步即可
    73     return u;
    74 }
    75 
    76 int main()
    77 {
    78     int x,y;
    79     n=Read();
    80     m=Read();
    81     root=Read();
    82     for(int i=1;i<n;i++)
    83     {
    84         x=Read();
    85         y=Read();
    86         add(x,y);
    87         add(y,x);
    88     }
    89     deth[root] = 1;
    90     dfs(root);
    91     while(m--)
    92     {
    93         x=Read();
    94         y=Read();
    95         printf("%d
    ",lca(x,y));
    96     }
    97     return 0;
    98 }
  • 相关阅读:
    在linux下Ant的环境配置
    在linux下Java的环境配置
    CSS列表逆序
    HTML元素基础学习
    第一天---HTML基础学习
    排球计分程序
    罗辑思维:怎样成为一个高手 观后感
    十八周个人作业
    本周个人作业
    个人作业
  • 原文地址:https://www.cnblogs.com/mjtcn/p/6841855.html
Copyright © 2020-2023  润新知