Maximum weighted edge in path between two nodes in an N-ary tree using binary lifting

Given an N-ary tree with weighted edge and Q queries where each query contains two nodes of the tree. The task is to find the maximum weighted edge in the simple path between these two nodes.
Examples:Â
Â
Naive Approach: A simple solution is to traverse the whole tree for each query and find the path between the two nodes.
Efficient Approach: The idea is to use binary lifting to pre-compute the maximum weighted edge from every node to every other node at distance of someÂ
. We will store the maximum weighted edge tillÂ
level.Â
Â
andÂ
whereÂ
- j is the node and
- i is the distance of
- dp[i][j] stores the parent of j at
- distance if present, else it will store 0
- mx[i][j] stores the maximum edge from node j to the parent of this node at
- distance.
We’ll do a depth-first search to find all the parents atÂ
distance and their weight and then precompute parents and maximum edges at everyÂ
distance.
Below is the implementation of the above approach:
C++
// C++ implementation to find the// maximum weighted edge in the simple// path between two nodes in N-ary TreeÂ
#include <bits/stdc++.h>Â
using namespace std;Â
const int N = 100005;Â
// Depths of Nodesvector<int> level(N);const int LG = 20;Â
// Parent at every 2^i levelvector<vector<int> > dp(LG, vector<int>(N));Â
// Maximum node at every 2^i levelvector<vector<int> > mx(LG, vector<int>(N));Â
// Graph that stores destinations// and its weightvector<vector<pair<int, int> > > v(N);int n;Â
// Function to traverse the nodes// using the Depth-First Search Traversalvoid dfs_lca(int a, int par, int lev){Â Â Â Â dp[0][a] = par;Â Â Â Â level[a] = lev;Â Â Â Â for (auto i : v[a]) {Â
        // Condition to check if its        // equal to its parent then skip        if (i.first == par)            continue;        mx[0][i.first] = i.second;Â
        // DFS Recursive Call        dfs_lca(i.first, a, lev + 1);    }}Â
// Function to find the ancestorvoid find_ancestor(){Â
    // Loop to set every 2^i distance    for (int i = 1; i < LG; i++) {        // Loop to calculate for        // each node in the N-ary tree        for (int j = 1; j <= n; j++) {            dp[i][j]                = dp[i - 1][dp[i - 1][j]];Â
            // Storing maximum edge            mx[i][j]                = max(mx[i - 1][j],                      mx[i - 1][dp[i - 1][j]]);        }    }}Â
int getMax(int a, int b){    // Swapping if node a is at more depth    // than node b because we will    // always take at more depth    if (level[b] < level[a])        swap(a, b);Â
    int ans = 0;Â
    // Difference between the depth of    // the two given nodes    int diff = level[b] - level[a];    while (diff > 0) {        int log = log2(diff);        ans = max(ans, mx[log][b]);Â
        // Changing Node B to its        // parent at 2 ^ i distance        b = dp[log][b];Â
        // Subtracting distance by 2^i        diff -= (1 << log);    }Â
    // Take both a, b to its    // lca and find maximum    while (a != b) {        int i = log2(level[a]);Â
        // Loop to find the 2^ith        // parent that is different        // for both a and b i.e below the lca         while (i > 0               && dp[i][a] == dp[i][b])            i--;Â
        // Updating ans        ans = max(ans, mx[i][a]);        ans = max(ans, mx[i][b]);Â
        // Changing value to its parent        a = dp[i][a];        b = dp[i][b];    }    return ans;}Â
// Function to compute the Least// common Ancestorvoid compute_lca(){Â Â Â Â dfs_lca(1, 0, 0);Â Â Â Â find_ancestor();}Â
// Driver Codeint main(){    // Undirected tree    n = 5;    v[1].push_back(make_pair(2, 2));    v[2].push_back(make_pair(1, 2));    v[1].push_back(make_pair(3, 5));    v[3].push_back(make_pair(1, 5));    v[3].push_back(make_pair(4, 3));    v[4].push_back(make_pair(3, 4));    v[3].push_back(make_pair(5, 1));    v[5].push_back(make_pair(3, 1));Â
    // Computing LCA    compute_lca();Â
    int queries[][2]        = { { 3, 5 },            { 2, 3 },            { 2, 4 } };    int q = 3;Â
    for (int i = 0; i < q; i++) {        int max_edge = getMax(queries[i][0],                              queries[i][1]);        cout << max_edge << endl;    }    return 0;} |
Java
// Java implementation to find the// maximum weighted edge in the simple// path between two nodes in N-ary Treeimport java.util.*;import java.awt.Point;public class Main{    static int N = 100005;         // Depths of Nodes    static int[] level = new int[N];    static int LG = 20;       // Parent at every 2^i level    static int[][] dp = new int[LG][N];       // Maximum node at every 2^i level    static int[][] mx = new int[LG][N];       // Graph that stores destinations    // and its weight    static Vector<Vector<Point>> v = new Vector<Vector<Point>>();          static int n = 0;       // Function to traverse the    // nodes using the Depth-First    // Search Traversal    static void dfs_lca(int a, int par, int lev)    {        dp[0][a] = par;        level[a] = lev;        for(int i = 0; i < v.get(a).size(); i++)        {            // Condition to check            // if its equal to its            // parent then skip            if (v.get(a).get(i).x == par)                continue;            mx[0][v.get(a).get(i).x] = v.get(a).get(i).y;               // DFS Recursive Call            dfs_lca(v.get(a).get(i).x, a, lev + 1);        }    }       // Function to find the ancestor    static void find_ancestor()    {        // Loop to set every 2^i distance        for(int i = 1; i < 16; i++)        {            // Loop to calculate for            // each node in the N-ary tree            for(int j = 1; j < n + 1; j++)            {                dp[i][j] = dp[i - 1][dp[i - 1][j]];                   // Storing maximum edge                mx[i][j] = Math.max(mx[i - 1][j], mx[i - 1][dp[i - 1][j]]);            }        }    }       static int getMax(int a, int b)    {        // Swapping if node a is at more depth        // than node b because we will        // always take at more depth        if (level[b] < level[a])        {            int temp = a;            a = b;            b = temp;        }           int ans = 0;           // Difference between the        // depth of the two given        // nodes        int diff = level[b] - level[a];           while (diff > 0)        {            int log = (int)(Math.log(diff) / Math.log(2));            ans = Math.max(ans, mx[log][b]);               // Changing Node B to its            // parent at 2 ^ i distance            b = dp[log][b];               // Subtracting distance by 2^i            diff -= (1 << log);        }           // Take both a, b to its        // lca and find maximum        while (a != b)        {            int i = (int)(Math.log(level[a]) / Math.log(2));               // Loop to find the maximum 2^ith            // parent the is different            // for both a and b            while (i > 0 && dp[i][a] == dp[i][b])            {                i-=1;            }               // Updating ans            ans = Math.max(ans, mx[i][a]);            ans = Math.max(ans, mx[i][b]);               // Changing value to            // its parent            a = dp[i][a];            b = dp[i][b];        }           return ans;    }       // Function to compute the Least    // common Ancestor    static void compute_lca()    {        dfs_lca(1, 0, 0);        find_ancestor();    }         public static void main(String[] args) {        for(int i = 0; i < LG; i++)        {            for(int j = 0; j < N; j++)            {                dp[i][j] = 0;                mx[i][j] = 0;            }        }                  for(int i = 0; i < N; i++)        {            v.add(new Vector<Point>());        }                  // Undirected tree        v.get(1).add(new Point(2, 2));        v.get(2).add(new Point(1, 2));        v.get(1).add(new Point(3, 5));        v.get(3).add(new Point(1, 5));        v.get(3).add(new Point(4, 3));        v.get(4).add(new Point(3, 4));        v.get(3).add(new Point(5, 1));        v.get(5).add(new Point(3, 1));               // Computing LCA        compute_lca();               int[][] queries            = { { 3, 5 },                { 2, 3 },                { 2, 4 } };        int q = 3;               for (int i = 0; i < q; i++) {            int max_edge = getMax(queries[i][0],                                  queries[i][1]);            System.out.println(max_edge);        }    }}Â
// This code is contributed by decode2207. |
Python3
# Python3 implementation to # find the maximum weighted # edge in the simple path # between two nodes in N-ary Treeimport mathN = 100005;Â Â # Depths of Nodeslevel = [0 for i in range(N)]LG = 20;Â Â # Parent at every 2^i leveldp = [[0 for j in range(N)] Â Â Â Â Â Â Â Â Â for i in range(LG)]Â Â # Maximum node at every 2^i levelmx = [[0 for j in range(N)] Â Â Â Â Â Â Â Â Â for i in range(LG)]Â Â # Graph that stores destinations# and its weightv = [[] for i in range(N)]n = 0Â Â # Function to traverse the # nodes using the Depth-First # Search Traversaldef dfs_lca(a, par, lev):Â
    dp[0][a] = par;    level[a] = lev;         for i in v[a]:          # Condition to check         # if its equal to its         # parent then skip        if (i[0] == par):            continue;        mx[0][i[0]] = i[1];          # DFS Recursive Call        dfs_lca(i[0], a, lev + 1);Â
# Function to find the ancestordef find_ancestor():      # Loop to set every 2^i distance    for i in range(1, 16):             # Loop to calculate for        # each node in the N-ary tree        for j in range(1, n + 1):                     dp[i][j] = dp[i - 1][dp[i - 1][j]];              # Storing maximum edge            mx[i][j] = max(mx[i - 1][j],                           mx[i - 1][dp[i - 1][j]]);Â
def getMax(a, b):Â
    # Swapping if node a is at more depth    # than node b because we will    # always take at more depth    if (level[b] < level[a]):        a, b = b, a      ans = 0;      # Difference between the     # depth of the two given     # nodes    diff = level[b] - level[a];         while (diff > 0):        log = int(math.log2(diff));        ans = max(ans, mx[log][b]);          # Changing Node B to its        # parent at 2 ^ i distance        b = dp[log][b];          # Subtracting distance by 2^i        diff -= (1 << log);          # Take both a, b to its    # lca and find maximum    while (a != b):        i = int(math.log2(level[a]));          # Loop to find the maximum 2^ith        # parent the is different        # for both a and b        while (i > 0 and               dp[i][a] == dp[i][b]):            i-=1          # Updating ans        ans = max(ans, mx[i][a]);        ans = max(ans, mx[i][b]);          # Changing value to         # its parent        a = dp[i][a];        b = dp[i][b];         return ans;  # Function to compute the Least# common Ancestordef compute_lca():         dfs_lca(1, 0, 0);    find_ancestor();Â
# Driver codeif __name__=="__main__":         # Undirected tree    n = 5;    v[1].append([2, 2]);    v[2].append([1, 2]);    v[1].append([3, 5]);    v[3].append([1, 5]);    v[3].append([4, 3]);    v[4].append([3, 4]);    v[3].append([5, 1]);    v[5].append([3, 1]);      # Computing LCA    compute_lca();      queries= [[3, 5], [2, 3], [2,4]]    q = 3;         for i in range(q):        max_edge = getMax(queries[i][0],                          queries[i][1]);        print(max_edge)         # This code is contributed by Rutvik_56 |
C#
// C# implementation to find the// maximum weighted edge in the simple// path between two nodes in N-ary Treeusing System;using System.Collections.Generic;class GFG {         static int N = 100005;        // Depths of Nodes    static int[] level = new int[N];    static int LG = 20;      // Parent at every 2^i level    static int[,] dp = new int[LG, N];      // Maximum node at every 2^i level    static int[,] mx = new int[LG, N];      // Graph that stores destinations    // and its weight    static List<List<Tuple<int,int>>> v = new List<List<Tuple<int,int>>>();         static int n = 0;      // Function to traverse the    // nodes using the Depth-First    // Search Traversal    static void dfs_lca(int a, int par, int lev)    {        dp[0,a] = par;        level[a] = lev;        for(int i = 0; i < v[a].Count; i++)        {            // Condition to check            // if its equal to its            // parent then skip            if (v[a][i].Item1 == par)                continue;            mx[0,v[a][i].Item1] = v[a][i].Item2;              // DFS Recursive Call            dfs_lca(v[a][i].Item1, a, lev + 1);        }    }      // Function to find the ancestor    static void find_ancestor()    {        // Loop to set every 2^i distance        for(int i = 1; i < 16; i++)        {            // Loop to calculate for            // each node in the N-ary tree            for(int j = 1; j < n + 1; j++)            {                dp[i,j] = dp[i - 1,dp[i - 1,j]];                  // Storing maximum edge                mx[i,j] = Math.Max(mx[i - 1,j], mx[i - 1,dp[i - 1,j]]);            }        }    }      static int getMax(int a, int b)    {        // Swapping if node a is at more depth        // than node b because we will        // always take at more depth        if (level[b] < level[a])        {            int temp = a;            a = b;            b = temp;        }          int ans = 0;          // Difference between the        // depth of the two given        // nodes        int diff = level[b] - level[a];          while (diff > 0)        {            int log = (int)(Math.Log(diff) / Math.Log(2));            ans = Math.Max(ans, mx[log,b]);              // Changing Node B to its            // parent at 2 ^ i distance            b = dp[log,b];              // Subtracting distance by 2^i            diff -= (1 << log);        }          // Take both a, b to its        // lca and find maximum        while (a != b)        {            int i = (int)(Math.Log(level[a]) / Math.Log(2));              // Loop to find the maximum 2^ith            // parent the is different            // for both a and b            while (i > 0 && dp[i,a] == dp[i,b])            {                i-=1;            }              // Updating ans            ans = Math.Max(ans, mx[i,a]);            ans = Math.Max(ans, mx[i,b]);              // Changing value to            // its parent            a = dp[i,a];            b = dp[i,b];        }          return ans;    }      // Function to compute the Least    // common Ancestor    static void compute_lca()    {        dfs_lca(1, 0, 0);        find_ancestor();    }Â
  static void Main() {           for(int i = 0; i < LG; i++)    {        for(int j = 0; j < N; j++)        {            dp[i,j] = 0;            mx[i,j] = 0;        }    }         for(int i = 0; i < N; i++)    {        v.Add(new List<Tuple<int,int>>());    }         // Undirected tree    v[1].Add(new Tuple<int,int>(2, 2));    v[2].Add(new Tuple<int,int>(1, 2));    v[1].Add(new Tuple<int,int>(3, 5));    v[3].Add(new Tuple<int,int>(1, 5));    v[3].Add(new Tuple<int,int>(4, 3));    v[4].Add(new Tuple<int,int>(3, 4));    v[3].Add(new Tuple<int,int>(5, 1));    v[5].Add(new Tuple<int,int>(3, 1));      // Computing LCA    compute_lca();      int[,] queries        = { { 3, 5 },            { 2, 3 },            { 2, 4 } };    int q = 3;      for (int i = 0; i < q; i++) {        int max_edge = getMax(queries[i,0],                              queries[i,1]);        Console.WriteLine(max_edge);    }  }}Â
// This code is contributed by divyesh072019. |
Javascript
<script>    // Javascript implementation to find the    // maximum weighted edge in the simple    // path between two nodes in N-ary Tree         let N = 100005;       // Depths of Nodes    let level = new Array(N);    level.fill(0);    let LG = 20;Â
    // Parent at every 2^i level    let dp = new Array(LG);    for(let i = 0; i < LG; i++)    {        dp[i] = new Array(N);        for(let j = 0; j < N; j++)        {            dp[i][j] = 0;        }    }Â
    // Maximum node at every 2^i level    let mx = new Array(LG);    for(let i = 0; i < LG; i++)    {        mx[i] = new Array(N);        for(let j = 0; j < N; j++)        {            mx[i][j] = 0;        }    }Â
    // Graph that stores destinations    // and its weight    let v = [];    for(let i = 0; i < N; i++)    {        v.push([]);    }    let n = 0;Â
    // Function to traverse the    // nodes using the Depth-First    // Search Traversal    function dfs_lca(a, par, lev)    {        dp[0][a] = par;        level[a] = lev;        for(let i = 0; i < 2; i++)        {            // Condition to check            // if its equal to its            // parent then skip            if (v[a][0] == par)                continue;            mx[0][v[a][0]] = v[a][1];Â
            // DFS Recursive Call            dfs_lca(v[a][0], a, lev + 1);        }    }Â
    // Function to find the ancestor    function find_ancestor()    {        // Loop to set every 2^i distance        for(let i = 1; i < 16; i++)        {            // Loop to calculate for            // each node in the N-ary tree            for(let j = 1; j < n + 1; j++)            {                dp[i][j] = dp[i - 1][dp[i - 1][j]];Â
                // Storing maximum edge                mx[i][j] = Math.max(mx[i - 1][j], mx[i - 1][dp[i - 1][j]]);            }        }    }Â
    function getMax(a, b)    {        // Swapping if node a is at more depth        // than node b because we will        // always take at more depth        if (level[b] < level[a])        {            let temp = a;            a = b;            b = temp;        }Â
        let ans = 0;Â
        // Difference between the        // depth of the two given        // nodes        let diff = level[b] - level[a];Â
        while (diff > 0)        {            let log = parseInt(Math.log(diff) / Math.log(2), 10);            ans = Math.max(ans, mx[log][b]);Â
            // Changing Node B to its            // parent at 2 ^ i distance            b = dp[log][b];Â
            // Subtracting distance by 2^i            diff -= (1 << log);        }Â
        // Take both a, b to its        // lca and find maximum        while (a == b)        {            i = parseInt(Math.log(level[a]) / Math.log(2), 10);Â
            // Loop to find the maximum 2^ith            // parent the is different            // for both a and b            while (i > 0 && dp[i][a] == dp[i][b])            {                i-=1;            }Â
            // Updating ans            ans = Math.max(ans, mx[i][a]);            ans = Math.max(ans, mx[i][b]);Â
            // Changing value to            // its parent            a = dp[i][a];            b = dp[i][b];        }Â
        return ans*2 + 1;    }Â
    // Function to compute the Least    // common Ansector    function compute_lca()    {        dfs_lca(1, 0, 0);        find_ancestor();    }         // Undirected tree    n = 5;    v[1].push(2);    v[1].push(2);    v[2].push(1);    v[2].push(2);    v[1].push(3);    v[1].push(5);    v[3].push(1);    v[3].push(5);    v[3].push(4);    v[3].push(3);    v[4].push(3);    v[4].push(4);    v[3].push(5);    v[3].push(1);    v[5].push(3);    v[5].push(1);       // Computing LCA    compute_lca();       let queries= [[3, 5], [2, 3], [2,4]];    let q = 3;          for(let i = 0; i <q; i++)    {        let max_edge = getMax(queries[i][0],                          queries[i][1]);        document.write(max_edge + "</br>");    }Â
// This code is contributed by suresh07.</script> |
1 5 5
Â
Time Complexity: O(N*logN).
Auxiliary Space: O(N*logN).
Â
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 zambiatek!



