zoukankan      html  css  js  c++  java
  • 【模板】倍增lca

     倍增跳一跳求树上两点间的最近公共祖先

    倍增求a, b两点的lca分三步:

    1. 初始化f[i][j]数组,表示从i点向上跳2j单位个的点,边界:f[i][0] = father[i](i的父节点)

      递推式:f[i][j] = f[f[i][j - 1]][j - 1]

        即 "从i点向上跳2j单位个的点" 等价于 "从i点向上跳2j-1单位个的点再向上跳2j-1单位个点"

    2.  把a, b跳到同一深度: 让深的点向上跳

    3. a, b一起跳到他们的lca的下一个点,则此时f[b][0]就是点a, b的lca.

    【代码:】

     1 //倍增lca
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cstring>
     5 using namespace std;
     6 
     7 const int MAXN = 500000 + 1;
     8 const int MAXM = 500000 + 1;
     9 const int K = 20 + 1;
    10 
    11 int n, m, s;
    12 int deep[MAXN], f[MAXN][K];
    13 int edge_num, head[MAXN];
    14 struct Edge {
    15     int to, next;
    16 }h[MAXM << 1];
    17 
    18 inline int read() {
    19     int x = 0, f = 1; char ch = getchar();
    20     while(ch < '0' || ch > '9') {
    21         if(ch == '-') f = -1;
    22         ch = getchar();
    23     }
    24     while(ch >= '0' && ch <= '9')
    25         x = (x << 3) + (x << 1) + ch - 48, ch = getchar();
    26     return x * f;
    27 }
    28 
    29 inline void Add(int from, int to) {
    30     h[++edge_num].to = to;
    31     h[edge_num].next = head[from];
    32     head[from] = edge_num;
    33 }
    34 
    35 void build(int u) {
    36     for(int i = head[u]; i != -1; i = h[i].next)
    37         if(!deep[h[i].to]) {
    38             deep[h[i].to]=deep[u]+1;
    39             f[h[i].to][0]=u;
    40             build(h[i].to);
    41         }
    42 }
    43 
    44 void fill() {
    45     for(int j = 1; j < K; ++j)
    46     for(int i = 1; i <= n; ++i)
    47         f[i][j] = f[f[i][j - 1]][j - 1];
    48 }
    49 
    50 int lca(int a, int b) {
    51     if(deep[a] > deep[b])
    52         swap(a, b);
    53     for(int i = K - 1; i >= 0; --i)
    54         if(deep[f[b][i]] >= deep[a]) b = f[b][i];
    55     if(a == b) return a;
    56     for(int i = K - 1; i >= 0; --i) {
    57         if(f[a][i] != f[b][i]) {
    58             a = f[a][i], b = f[b][i];
    59         }
    60     }
    61     return f[b][0];
    62 }
    63 
    64 int main() {
    65     n = read(), m = read(), s = read();
    66     memset(head, -1, sizeof(head));
    67     for(int i = 1; i < n; ++i) {
    68         int x = read(), y = read();
    69         Add(x, y);
    70         Add(y, x);
    71     }
    72     deep[s] = 1;
    73     build(s);
    74     fill();
    75     while(m--) {
    76         int a = read(), b = read();
    77         printf("%d
    ", lca(a, b));
    78     }
    79 }

    题目传送门

  • 相关阅读:
    机器学习:特征选择方法简介
    VS快捷键
    非常适用的Sourceinsight插件,提高效率【强力推荐】
    Linux静态库和共享库
    C/C++ 位域知识小结
    __BEGIN_DECLS 和 __END_DECLS
    C语言可变参数va_list
    mac的terminal快捷键
    linux进程、线程与cpu的亲和性(affinity)
    C++ Singleton (单例) 模式最优实现
  • 原文地址:https://www.cnblogs.com/devilk-sjj/p/9048434.html
Copyright © 2011-2022 走看看