• LCA---模板


    LCA:最近公共祖先

    性质:1、LCA( u ) = u。

               2、u 是 v 的祖先,当且仅当 LCA( u , v ) = u。

               3、如果 u 不为 v 的祖先并且 v 不为 u 的祖先,那么这两个点属于不同的子树。

               4、两点的最近公共祖先必定处在两点间的树上最短路上。

               5、d( u , v ) = h( u ) + h( v ) - 2*h( LCA( u , v )) ,其中 d 是树上两点间的最短距离, h 是该点与树根之间的距离。

    用途:求树从 x 到 y 节点最短路径上所有节点的值之和。

    代码:

     1 #include<bits/stdc++.h>
     2 #define ll long long
     3 #define MOD 1e9+7 
     4 #define INF 0x3f3f3f3f
     5 #define mem(a,x) memset(a,x,sizeof(a))  
     6 #define _for(i,a,b) for(int i=a; i< b; i++)
     7 #define _rep(i,a,b) for(int i=a; i<=b; i++)
     8 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
     9 
    10 using namespace std;
    11 const int MAXN = 1000005 ;
    12 inline int rd() 
    13 {
    14     int res = 0,flag = 0;
    15     char ch;
    16     if ((ch = getchar()) == '-')flag = 1;
    17     else if(ch >= '0' && ch <= '9')res = ch - '0';
    18     while ((ch = getchar()) >= '0' && ch <= '9')res = (res<<1) + (res<<3) + (ch - '0');
    19     return flag ? -res : res;
    20 }
    21 //
    22 int head[MAXN]; 
    23 int num=0;
    24 struct edg{
    25    int next,to;
    26 }edge[MAXN];
    27 void edge_add(int u,int v)   //链式前向星存图
    28 {
    29    num++;
    30    edge[num].next=head[u];edge[num].to=v;head[u]=num;
    31    edge[++num].next=head[v];edge[num].to=u;head[v]=num;
    32 }
    33 //---------------------
    34 // lca部分
    35 int n,m,s;
    36 int dep[MAXN]={0},f[MAXN][23];
    37 void dfs(int u,int father)//对应深搜预处理f数组 
    38 {
    39     dep[u]=dep[father]+1;
    40     for(int i=1;(1<<i)<=dep[u];i++)
    41     {
    42         f[u][i]=f[f[u][i-1]][i-1];
    43     }
    44     for(int i=head[u];i;i=edge[i].next)
    45     {
    46         int v=edge[i].to;
    47         if(v==father)continue;//双向图需要判断是不是父亲节点 
    48         f[v][0]=u;
    49         dfs(v,u);
    50     }
    51 }
    52 int lca(int x,int y)
    53 {
    54     if(dep[x]<dep[y])swap(x,y);
    55     for(int i=20;i>=0;i--)//从大到小枚举使x和y到了同一层 
    56     {
    57         if(dep[f[x][i]]>=dep[y])x=f[x][i];
    58         if(x==y)return x;
    59     }
    60     for(int i=20;i>=0;i--)//从大到小枚举 
    61     {
    62         if(f[x][i]!=f[y][i])//尽可能接近 
    63         {
    64             x=f[x][i];y=f[y][i];
    65         } 
    66     } 
    67     return f[x][0];//随便找一个**输出 
    68 }
    69 int main(){
    70     scanf("%d%d%d",&n,&m,&s);
    71     for(int i=1;i<n;i++)
    72     {
    73         scanf("%d",&a1);scanf("%d",&a2);
    74         edge_add(a1,a2);//链式存边 
    75     }
    76     dfs(s,0);
    77     for(int i=1;i<=m;i++)
    78     {
    79         scanf("%d %d",&a1,&a2);
    80         printf("%d
    ",lca(a1,a2));//求两个节点的LCA 
    81     }
    82     return 0;
    83 } 
    View Code
    越自律,越自由
  • 相关阅读:
    编码的道与禅
    使用 C# 编写简易 ASP.NET Web 服务器
    程序员的职业素养
    NServiceBus官方文档翻译(二)NServiceBus 入门
    NServiceBus官方文档翻译(一)NServiceBus 概况
    七周七语言之使用prolog解决爱因斯坦斑马难题
    七周七语言之用Io编写领域特定语言
    七周七语言之用ruby做点什么
    利用binarySearch实现抽奖计算逻辑
    Java设计模式三
  • 原文地址:https://www.cnblogs.com/ha-chuochuo/p/13522713.html
Copyright © 2020-2023  润新知