📜  适用于普通树或n元树的LCA(稀疏矩阵DP方法)

📅  最后修改于: 2021-04-17 12:28:22             🧑  作者: Mango

在以前的文章中,我们讨论了如何为二叉树和二叉搜索树(this,this和this)计算最低公共祖先(LCA)。现在,让我们看一种可以为任何树(不仅是二叉树)计算LCA的方法。在我们的方法中,我们使用带有稀疏矩阵方法的动态规划。当您需要回答针对树的LCA的多个查询时,此方法非常方便快捷。

lca-n-ary树

先决条件:–
1)DFS
2)基本的DP知识(本和本)
3)范围最小查询(平方根分解和稀疏表)

天真的方法:-O(n)
用于一般树LCA计算的幼稚方法将与用于二叉树LCA计算的幼稚方法相同(此幼稚方法已在此处进行了很好的描述。

天真的方法的实现如下:

C++
/* Program to find LCA of n1 and n2 using one DFS on
   the Tree */
#include
using namespace std;
 
// Maximum number of nodes is 100000 and nodes are
// numbered from 1 to 100000
#define MAXN 100001
 
vector < int > tree[MAXN];
int path[3][MAXN]; // storing root to node path
 
// storing the path from root to node
void dfs(int cur, int prev, int pathNumber, int ptr,
                             int node, bool &flag)
{
    for (int i=0; iJava
/* Program to find LCA of n1 and n2 using one DFS on
the Tree */
 
import java.util.*;
 
class GFG
{
 
    // Maximum number of nodes is 100000 and nodes are
    // numbered from 1 to 100000
    static final int MAXN = 100001;
 
    static Vector[] tree = new Vector[MAXN];
    static int[][] path = new int[3][MAXN]; // storing root to node path
    static boolean flag;
 
    // storing the path from root to node
    static void dfs(int cur, int prev, int pathNumber, int ptr, int node)
    {
        for (int i = 0; i < tree[cur].size(); i++)
        {
            if (tree[cur].get(i) != prev && !flag)
            {
                // pushing current node into the path
                path[pathNumber][ptr] = tree[cur].get(i);
                if (tree[cur].get(i) == node)
                {
                    // node found
                    flag = true;
 
                    // terminating the path
                    path[pathNumber][ptr + 1] = -1;
                    return;
                }
                dfs(tree[cur].get(i), cur, pathNumber, ptr + 1, node);
            }
        }
    }
 
    // This Function compares the path from root to 'a' & root
    // to 'b' and returns LCA of a and b. Time Complexity : O(n)
    static int LCA(int a, int b)
    {
        // trivial case
        if (a == b)
            return a;
 
        // setting root to be first element in path
        path[1][0] = path[2][0] = 1;
 
        // calculating path from root to a
        flag = false;
        dfs(1, 0, 1, 1, a);
 
        // calculating path from root to b
        flag = false;
        dfs(1, 0, 2, 1, b);
 
        // runs till path 1 & path 2 mathches
        int i = 0;
        while (i < MAXN && path[1][i] == path[2][i])
            i++;
 
        // returns the last matching node in the paths
        return path[1][i - 1];
    }
 
    static void addEdge(int a, int b)
    {
        tree[a].add(b);
        tree[b].add(a);
    }
 
    // Driver code
    public static void main(String[] args)
    {
        for (int i = 0; i < MAXN; i++)
            tree[i] = new Vector();
 
        // Number of nodes
        addEdge(1, 2);
        addEdge(1, 3);
        addEdge(2, 4);
        addEdge(2, 5);
        addEdge(2, 6);
        addEdge(3, 7);
        addEdge(3, 8);
 
        System.out.print("LCA(4, 7) = " + LCA(4, 7) + "\n");
        System.out.print("LCA(4, 6) = " + LCA(4, 6) + "\n");
    }
}
 
// This code is contributed by 29AjayKumar


Python3
# Python3 program to find LCA of n1 and
# n2 using one DFS on the Tree
 
# Maximum number of nodes is 100000 and
# nodes are numbered from 1 to 100000
MAXN = 100001
 
tree = [0] * MAXN
for i in range(MAXN):
    tree[i] = []
 
# Storing root to node path
path = [0] * 3
for i in range(3):
    path[i] = [0] * MAXN
 
flag = False
 
# Storing the path from root to node
def dfs(cur: int, prev: int, pathNumber: int,
        ptr: int, node: int) -> None:
             
    global tree, path, flag
 
    for i in range(len(tree[cur])):
        if (tree[cur][i] != prev and not flag):
 
            # Pushing current node into the path
            path[pathNumber][ptr] = tree[cur][i]
             
            if (tree[cur][i] == node):
 
                # Node found
                flag = True
 
                # Terminating the path
                path[pathNumber][ptr + 1] = -1
                return
 
            dfs(tree[cur][i], cur, pathNumber,
                ptr + 1, node)
 
# This Function compares the path from root
# to 'a' & root to 'b' and returns LCA of
# a and b. Time Complexity : O(n)
def LCA(a: int, b: int) -> int:
     
    global flag
     
    # Trivial case
    if (a == b):
        return a
 
    # Setting root to be first element
    # in path
    path[1][0] = path[2][0] = 1
 
    # Calculating path from root to a
    flag = False
    dfs(1, 0, 1, 1, a)
 
    # Calculating path from root to b
    flag = False
    dfs(1, 0, 2, 1, b)
 
    # Runs till path 1 & path 2 mathches
    i = 0
    while (path[1][i] == path[2][i]):
        i += 1
 
    # Returns the last matching
    # node in the paths
    return path[1][i - 1]
 
def addEdge(a: int, b: int) -> None:
 
    tree[a].append(b)
    tree[b].append(a)
 
# Driver code
if __name__ == "__main__":
 
    n = 8
     
    # Number of nodes
    addEdge(1, 2)
    addEdge(1, 3)
    addEdge(2, 4)
    addEdge(2, 5)
    addEdge(2, 6)
    addEdge(3, 7)
    addEdge(3, 8)
 
    print("LCA(4, 7) = {}".format(LCA(4, 7)))
    print("LCA(4, 6) = {}".format(LCA(4, 6)))
 
# This code is contributed by sanjeev2552


C#
/* C# Program to find LCA of n1 and n2 using one DFS on
the Tree */
using System;
using System.Collections.Generic;
 
class GFG
{
 
    // Maximum number of nodes is 100000 and nodes are
    // numbered from 1 to 100000
    static readonly int MAXN = 100001;
 
    static List[] tree = new List[MAXN];
    static int[,] path = new int[3, MAXN]; // storing root to node path
    static bool flag;
 
    // storing the path from root to node
    static void dfs(int cur, int prev, int pathNumber, int ptr, int node)
    {
        for (int i = 0; i < tree[cur].Count; i++)
        {
            if (tree[cur][i] != prev && !flag)
            {
                // pushing current node into the path
                path[pathNumber,ptr] = tree[cur][i];
                if (tree[cur][i] == node)
                {
                    // node found
                    flag = true;
 
                    // terminating the path
                    path[pathNumber, ptr + 1] = -1;
                    return;
                }
                dfs(tree[cur][i], cur, pathNumber, ptr + 1, node);
            }
        }
    }
 
    // This Function compares the path from root to 'a' & root
    // to 'b' and returns LCA of a and b. Time Complexity : O(n)
    static int LCA(int a, int b)
    {
        // trivial case
        if (a == b)
            return a;
 
        // setting root to be first element in path
        path[1, 0] = path[2, 0] = 1;
 
        // calculating path from root to a
        flag = false;
        dfs(1, 0, 1, 1, a);
 
        // calculating path from root to b
        flag = false;
        dfs(1, 0, 2, 1, b);
 
        // runs till path 1 & path 2 mathches
        int i = 0;
        while (i < MAXN && path[1, i] == path[2, i])
            i++;
 
        // returns the last matching node in the paths
        return path[1, i - 1];
    }
 
    static void addEdge(int a, int b)
    {
        tree[a].Add(b);
        tree[b].Add(a);
    }
 
    // Driver code
    public static void Main(String[] args)
    {
        for (int i = 0; i < MAXN; i++)
            tree[i] = new List();
 
        // Number of nodes
        addEdge(1, 2);
        addEdge(1, 3);
        addEdge(2, 4);
        addEdge(2, 5);
        addEdge(2, 6);
        addEdge(3, 7);
        addEdge(3, 8);
 
        Console.Write("LCA(4, 7) = " + LCA(4, 7) + "\n");
        Console.Write("LCA(4, 6) = " + LCA(4, 6) + "\n");
    }
}
 
// This code is contributed by Rajput-Ji


C++
// Sparse Matrix DP approach to find LCA of two nodes
#include 
using namespace std;
#define MAXN 100000
#define level 18
 
vector  tree[MAXN];
int depth[MAXN];
int parent[MAXN][level];
 
// pre-compute the depth for each node and their
// first parent(2^0th parent)
// time complexity : O(n)
void dfs(int cur, int prev)
{
    depth[cur] = depth[prev] + 1;
    parent[cur][0] = prev;
    for (int i=0; i>i)&1)
            v = parent[v][i];
 
    // now depth[u] == depth[v]
    if (u == v)
        return u;
 
    // Step 2 of the pseudocode
    for (int i=level-1; i>=0; i--)
        if (parent[u][i] != parent[v][i])
        {
            u = parent[u][i];
            v = parent[v][i];
        }
 
    return parent[u][0];
}
 
void addEdge(int u,int v)
{
    tree[u].push_back(v);
    tree[v].push_back(u);
}
 
// driver function
int main()
{
    memset(parent,-1,sizeof(parent));
    int n = 8;
    addEdge(1,2);
    addEdge(1,3);
    addEdge(2,4);
    addEdge(2,5);
    addEdge(2,6);
    addEdge(3,7);
    addEdge(3,8);
    depth[0] = 0;
 
    // running dfs and precalculating depth
    // of each node.
    dfs(1,0);
 
    // Precomputing the 2^i th ancestor for evey node
    precomputeSparseMatrix(n);
 
    // calling the LCA function
    cout << "LCA(4, 7) = " << lca(4,7) << endl;
    cout << "LCA(4, 6) = " << lca(4,6) << endl;
    return 0;
}


Java
// Sparse Matrix DP approach to find LCA of two nodes
import java.util.*;
 
class GFG
{
    static final int MAXN = 100000;
    static final int level = 18;
   
      @SuppressWarnings("unchecked")
    static Vector[] tree = new Vector[MAXN];
    static int[] depth = new int[MAXN];
    static int[][] parent = new int[MAXN][level];
 
    // pre-compute the depth for each node and their
    // first parent(2^0th parent)
    // time complexity : O(n)
    static void dfs(int cur, int prev)
    {
        depth[cur] = depth[prev] + 1;
        parent[cur][0] = prev;
        for (int i = 0; i < tree[cur].size(); i++)
        {
            if (tree[cur].get(i) != prev)
                dfs(tree[cur].get(i), cur);
        }
    }
 
    // Dynamic Programming Sparse Matrix Approach
    // populating 2^i parent for each node
    // Time complexity : O(nlogn)
    static void precomputeSparseMatrix(int n)
    {
        for (int i = 1; i < level; i++)
        {
            for (int node = 1; node <= n; node++)
            {
                if (parent[node][i - 1] != -1)
                    parent[node][i] = parent[parent[node][i - 1]][i - 1];
            }
        }
    }
 
    // Returning the LCA of u and v
    // Time complexity : O(log n)
    static int lca(int u, int v)
    {
        if (depth[v] < depth[u])
        {
            u = u + v;
            v = u - v;
            u = u - v;
        }
 
        int diff = depth[v] - depth[u];
 
        // Step 1 of the pseudocode
        for (int i = 0; i < level; i++)
            if (((diff >> i) & 1) == 1)
                v = parent[v][i];
 
        // now depth[u] == depth[v]
        if (u == v)
            return u;
 
        // Step 2 of the pseudocode
        for (int i = level - 1; i >= 0; i--)
            if (parent[u][i] != parent[v][i])
            {
                u = parent[u][i];
                v = parent[v][i];
            }
 
        return parent[u][0];
    }
 
    static void addEdge(int u, int v)
    {
        tree[u].add(v);
        tree[v].add(u);
    }
 
    static void memset(int value)
    {
        for (int i = 0; i < MAXN; i++)
        {
            for (int j = 0; j < level; j++)
            {
                parent[i][j] = -1;
            }
        }
    }
 
    // driver function
    public static void main(String[] args)
    {
        memset(-1);
        for (int i = 0; i < MAXN; i++)
            tree[i] = new Vector();
        int n = 8;
        addEdge(1, 2);
        addEdge(1, 3);
        addEdge(2, 4);
        addEdge(2, 5);
        addEdge(2, 6);
        addEdge(3, 7);
        addEdge(3, 8);
        depth[0] = 0;
 
        // running dfs and precalculating depth
        // of each node.
        dfs(1, 0);
 
        // Precomputing the 2^i th ancestor for evey node
        precomputeSparseMatrix(n);
 
        // calling the LCA function
        System.out.print("LCA(4, 7) = " + lca(4, 7) + "\n");
        System.out.print("LCA(4, 6) = " + lca(4, 6) + "\n");
    }
}
 
// This code is contributed by 29AjayKumar


C#
// Sparse Matrix DP approach to find LCA of two nodes
using System;
using System.Collections.Generic;
 
class GFG
{
    static readonly int MAXN = 100000;
    static readonly int level = 18;
 
    static List[] tree = new List[MAXN];
    static int[] depth = new int[MAXN];
    static int[,] parent = new int[MAXN, level];
 
    // pre-compute the depth for each node and their
    // first parent(2^0th parent)
    // time complexity : O(n)
    static void dfs(int cur, int prev)
    {
        depth[cur] = depth[prev] + 1;
        parent[cur,0] = prev;
        for (int i = 0; i < tree[cur].Count; i++)
        {
            if (tree[cur][i] != prev)
                dfs(tree[cur][i], cur);
        }
    }
 
    // Dynamic Programming Sparse Matrix Approach
    // populating 2^i parent for each node
    // Time complexity : O(nlogn)
    static void precomputeSparseMatrix(int n)
    {
        for (int i = 1; i < level; i++)
        {
            for (int node = 1; node <= n; node++)
            {
                if (parent[node, i - 1] != -1)
                    parent[node, i] = parent[parent[node, i - 1], i - 1];
            }
        }
    }
 
    // Returning the LCA of u and v
    // Time complexity : O(log n)
    static int lca(int u, int v)
    {
        if (depth[v] < depth[u])
        {
            u = u + v;
            v = u - v;
            u = u - v;
        }
 
        int diff = depth[v] - depth[u];
 
        // Step 1 of the pseudocode
        for (int i = 0; i < level; i++)
            if (((diff >> i) & 1) == 1)
                v = parent[v, i];
 
        // now depth[u] == depth[v]
        if (u == v)
            return u;
 
        // Step 2 of the pseudocode
        for (int i = level - 1; i >= 0; i--)
            if (parent[u, i] != parent[v, i])
            {
                u = parent[u, i];
                v = parent[v, i];
            }
 
        return parent[u, 0];
    }
 
    static void addEdge(int u, int v)
    {
        tree[u].Add(v);
        tree[v].Add(u);
    }
 
    static void memset(int value)
    {
        for (int i = 0; i < MAXN; i++)
        {
            for (int j = 0; j < level; j++)
            {
                parent[i, j] = -1;
            }
        }
    }
 
    // Driver function
    public static void Main(String[] args)
    {
        memset(-1);
        for (int i = 0; i < MAXN; i++)
            tree[i] = new List();
        int n = 8;
        addEdge(1, 2);
        addEdge(1, 3);
        addEdge(2, 4);
        addEdge(2, 5);
        addEdge(2, 6);
        addEdge(3, 7);
        addEdge(3, 8);
        depth[0] = 0;
 
        // running dfs and precalculating depth
        // of each node.
        dfs(1, 0);
 
        // Precomputing the 2^i th ancestor for evey node
        precomputeSparseMatrix(n);
 
        // calling the LCA function
        Console.Write("LCA(4, 7) = " + lca(4, 7) + "\n");
        Console.Write("LCA(4, 6) = " + lca(4, 6) + "\n");
    }
}
 
// This code is contributed by PrinciRaj1992


输出:

LCA(4, 7) = 1
LCA(4, 6) = 2

稀疏矩阵方法(O(nlogn)预处理,O(log n)–查询)
预计算:-这里,我们为每个节点存储第2个第i个父节点,其中0 <= i 因此,我们假设最坏的情况是要看到常量LEVEL的值是多少。在最坏的情况下,树中的每个节点最多只能有1个父级和1个子级,或者我们可以说它只是简化为一个链表。
因此,在这种情况下,LEVEL = ceil(log(节点数))。

我们还使用O(n)时间中的一个dfs预先计算了每个节点的高度。

int n             // number of nodes
int parent[MAXN][LEVEL] // all initialized to -1 

parent[node][0] : contains the 2^0th(first) 
parent of all the nodes pre-computed using DFS

// Sparse matrix Approach
for node -> 1 to n :        
  for i-> 1 to LEVEL :
    if ( parent[node][i-1] != -1 ) :
      parent[node][i]  =  
         parent[ parent[node][i-1] ][i-1]

现在,如我们所见,上面的动态编程代码运行两个嵌套循环,分别在它们的整个范围内运行。
因此,可以容易地推断出其渐近时间复杂度为O(节点数* LEVEL)〜O(n * LEVEL)〜O(nlogn)。

返回LCA(u,v) :-
1)第一步是使两个节点处于相同的高度。由于我们已经预先计算了每个节点的高度。我们首先计算u和v的高度差(假设v> = u)。现在我们需要节点“ v”将上面的h个节点跳过。这可以很容易地在O(log h)时间(其中h是u和v的高度差)中完成,因为我们已经为每个节点存储了2 ^ i父对象。此过程与在O(log y)时间中计算x ^ y完全相同。 (请参阅代码以更好地理解)。
2)现在,u和v节点都处于相同的高度。因此,现在我们将再次使用2 ^ i跳跃策略来达到u和v的第一个Common Parent。

Pseudo-code:
For i->  LEVEL to 0 :
      If parent[u][i] != parent[v][i] :
           u = parent[u][i]
           v = parent[v][i]

上述算法的实现如下:

C++

// Sparse Matrix DP approach to find LCA of two nodes
#include 
using namespace std;
#define MAXN 100000
#define level 18
 
vector  tree[MAXN];
int depth[MAXN];
int parent[MAXN][level];
 
// pre-compute the depth for each node and their
// first parent(2^0th parent)
// time complexity : O(n)
void dfs(int cur, int prev)
{
    depth[cur] = depth[prev] + 1;
    parent[cur][0] = prev;
    for (int i=0; i>i)&1)
            v = parent[v][i];
 
    // now depth[u] == depth[v]
    if (u == v)
        return u;
 
    // Step 2 of the pseudocode
    for (int i=level-1; i>=0; i--)
        if (parent[u][i] != parent[v][i])
        {
            u = parent[u][i];
            v = parent[v][i];
        }
 
    return parent[u][0];
}
 
void addEdge(int u,int v)
{
    tree[u].push_back(v);
    tree[v].push_back(u);
}
 
// driver function
int main()
{
    memset(parent,-1,sizeof(parent));
    int n = 8;
    addEdge(1,2);
    addEdge(1,3);
    addEdge(2,4);
    addEdge(2,5);
    addEdge(2,6);
    addEdge(3,7);
    addEdge(3,8);
    depth[0] = 0;
 
    // running dfs and precalculating depth
    // of each node.
    dfs(1,0);
 
    // Precomputing the 2^i th ancestor for evey node
    precomputeSparseMatrix(n);
 
    // calling the LCA function
    cout << "LCA(4, 7) = " << lca(4,7) << endl;
    cout << "LCA(4, 6) = " << lca(4,6) << endl;
    return 0;
}

Java

// Sparse Matrix DP approach to find LCA of two nodes
import java.util.*;
 
class GFG
{
    static final int MAXN = 100000;
    static final int level = 18;
   
      @SuppressWarnings("unchecked")
    static Vector[] tree = new Vector[MAXN];
    static int[] depth = new int[MAXN];
    static int[][] parent = new int[MAXN][level];
 
    // pre-compute the depth for each node and their
    // first parent(2^0th parent)
    // time complexity : O(n)
    static void dfs(int cur, int prev)
    {
        depth[cur] = depth[prev] + 1;
        parent[cur][0] = prev;
        for (int i = 0; i < tree[cur].size(); i++)
        {
            if (tree[cur].get(i) != prev)
                dfs(tree[cur].get(i), cur);
        }
    }
 
    // Dynamic Programming Sparse Matrix Approach
    // populating 2^i parent for each node
    // Time complexity : O(nlogn)
    static void precomputeSparseMatrix(int n)
    {
        for (int i = 1; i < level; i++)
        {
            for (int node = 1; node <= n; node++)
            {
                if (parent[node][i - 1] != -1)
                    parent[node][i] = parent[parent[node][i - 1]][i - 1];
            }
        }
    }
 
    // Returning the LCA of u and v
    // Time complexity : O(log n)
    static int lca(int u, int v)
    {
        if (depth[v] < depth[u])
        {
            u = u + v;
            v = u - v;
            u = u - v;
        }
 
        int diff = depth[v] - depth[u];
 
        // Step 1 of the pseudocode
        for (int i = 0; i < level; i++)
            if (((diff >> i) & 1) == 1)
                v = parent[v][i];
 
        // now depth[u] == depth[v]
        if (u == v)
            return u;
 
        // Step 2 of the pseudocode
        for (int i = level - 1; i >= 0; i--)
            if (parent[u][i] != parent[v][i])
            {
                u = parent[u][i];
                v = parent[v][i];
            }
 
        return parent[u][0];
    }
 
    static void addEdge(int u, int v)
    {
        tree[u].add(v);
        tree[v].add(u);
    }
 
    static void memset(int value)
    {
        for (int i = 0; i < MAXN; i++)
        {
            for (int j = 0; j < level; j++)
            {
                parent[i][j] = -1;
            }
        }
    }
 
    // driver function
    public static void main(String[] args)
    {
        memset(-1);
        for (int i = 0; i < MAXN; i++)
            tree[i] = new Vector();
        int n = 8;
        addEdge(1, 2);
        addEdge(1, 3);
        addEdge(2, 4);
        addEdge(2, 5);
        addEdge(2, 6);
        addEdge(3, 7);
        addEdge(3, 8);
        depth[0] = 0;
 
        // running dfs and precalculating depth
        // of each node.
        dfs(1, 0);
 
        // Precomputing the 2^i th ancestor for evey node
        precomputeSparseMatrix(n);
 
        // calling the LCA function
        System.out.print("LCA(4, 7) = " + lca(4, 7) + "\n");
        System.out.print("LCA(4, 6) = " + lca(4, 6) + "\n");
    }
}
 
// This code is contributed by 29AjayKumar

C#

// Sparse Matrix DP approach to find LCA of two nodes
using System;
using System.Collections.Generic;
 
class GFG
{
    static readonly int MAXN = 100000;
    static readonly int level = 18;
 
    static List[] tree = new List[MAXN];
    static int[] depth = new int[MAXN];
    static int[,] parent = new int[MAXN, level];
 
    // pre-compute the depth for each node and their
    // first parent(2^0th parent)
    // time complexity : O(n)
    static void dfs(int cur, int prev)
    {
        depth[cur] = depth[prev] + 1;
        parent[cur,0] = prev;
        for (int i = 0; i < tree[cur].Count; i++)
        {
            if (tree[cur][i] != prev)
                dfs(tree[cur][i], cur);
        }
    }
 
    // Dynamic Programming Sparse Matrix Approach
    // populating 2^i parent for each node
    // Time complexity : O(nlogn)
    static void precomputeSparseMatrix(int n)
    {
        for (int i = 1; i < level; i++)
        {
            for (int node = 1; node <= n; node++)
            {
                if (parent[node, i - 1] != -1)
                    parent[node, i] = parent[parent[node, i - 1], i - 1];
            }
        }
    }
 
    // Returning the LCA of u and v
    // Time complexity : O(log n)
    static int lca(int u, int v)
    {
        if (depth[v] < depth[u])
        {
            u = u + v;
            v = u - v;
            u = u - v;
        }
 
        int diff = depth[v] - depth[u];
 
        // Step 1 of the pseudocode
        for (int i = 0; i < level; i++)
            if (((diff >> i) & 1) == 1)
                v = parent[v, i];
 
        // now depth[u] == depth[v]
        if (u == v)
            return u;
 
        // Step 2 of the pseudocode
        for (int i = level - 1; i >= 0; i--)
            if (parent[u, i] != parent[v, i])
            {
                u = parent[u, i];
                v = parent[v, i];
            }
 
        return parent[u, 0];
    }
 
    static void addEdge(int u, int v)
    {
        tree[u].Add(v);
        tree[v].Add(u);
    }
 
    static void memset(int value)
    {
        for (int i = 0; i < MAXN; i++)
        {
            for (int j = 0; j < level; j++)
            {
                parent[i, j] = -1;
            }
        }
    }
 
    // Driver function
    public static void Main(String[] args)
    {
        memset(-1);
        for (int i = 0; i < MAXN; i++)
            tree[i] = new List();
        int n = 8;
        addEdge(1, 2);
        addEdge(1, 3);
        addEdge(2, 4);
        addEdge(2, 5);
        addEdge(2, 6);
        addEdge(3, 7);
        addEdge(3, 8);
        depth[0] = 0;
 
        // running dfs and precalculating depth
        // of each node.
        dfs(1, 0);
 
        // Precomputing the 2^i th ancestor for evey node
        precomputeSparseMatrix(n);
 
        // calling the LCA function
        Console.Write("LCA(4, 7) = " + lca(4, 7) + "\n");
        Console.Write("LCA(4, 6) = " + lca(4, 6) + "\n");
    }
}
 
// This code is contributed by PrinciRaj1992

输出:

LCA(4,7) = 1
LCA(4,6) = 2

时间复杂度:回答单个LCA查询的时间复杂度为O(logn),但总体时间复杂度由每个节点的第2个第i个(0 <= i <= level)祖先的预先计算决定。因此,总体渐近时间复杂度将为O(n * logn),空间复杂度将为O(nlogn),用于存储有关每个节点祖先的数据。