Skip to content
Related Articles

Related Articles

Count of ancestors with smaller value for each node of an N-ary Tree

View Discussion
Improve Article
Save Article
  • Last Updated : 15 Feb, 2022
View Discussion
Improve Article
Save Article

Given an N-ary tree consisting of N nodes with values from 1 to N rooted at 1, for all nodes, print the number of ancestors having a smaller value than the current node.

Example: 

   Input: Below is the given Tree:

                     1
                  /   \
                4     5
              /     /  | \
            6    3   2  7                           

   Output: 0 1 1 1 1 2 2   
   Explanation:  
   Since node 1 is the root node, it has no ancestors.
   Ancestors of node 2: {1, 5}. Number of ancestors having value smaller than 2 is 1.
   Ancestors of node 3: {1, 5}. Number of ancestors having value smaller than 3 is 1.
   Ancestors of node 4: {1}. Number of ancestors having value smaller than 4 is 1.
   Ancestors of node 5: {1}. Number of ancestors having value smaller than 5 is 1.
   Ancestors of node 6: {1, 4}. Number of ancestors having value smaller than 6 is 2.
   Ancestors of node 7: {1, 5}. Number of ancestors having value smaller than 7 is 2

   Input: Below is the given Tree:

                   1
                  / \
                3   2
                      \
                       4    

   Output: 0 1 1 2      
   Explanation:  
   Node 1 has no ancestors.
   Ancestors of node 2: {1}. Number of ancestors having value smaller than 2 is 1.
   Ancestors of node 3: {1}. Number of ancestors having value smaller than 3 is 1.

 

Brute Force Approach: The idea is similar to what is mentioned here: Count ancestors with smaller value for each node of a Binary Tree. The idea is to use DFS for each node and can be extended to an N-ary tree easily.

Time Complexity: O(N2)
Auxiliary Space: O(1)

Efficient Approach: The efficient approach is based on the concept of Ordered_set, policy-based data structure, and DFS.

  • Use a top-down DFS to traverse from the root to all the nodes and use an ordered set to store values of all nodes in the path from the root to the current node.
  • Whenever entering a node, before calling DFS on its children, push the node index into the ordered set and whenever we exit the node, erase the node index from the ordered_set. This ensures that ordered_set will contain values of all ancestors of the current node.
  • Since the ordered set gives the functionality to return a number of smaller values than given x by finding the order of the x, for each node, whenever entering the node, simply find the order of the current node’s index and get the number of smaller values present in the ordered_set i.e number of smaller valued ancestors for each node.
  • Use a map to store the number of smaller valued ancestors for each node and use that to print the final answer.

Below is the implementation of the above approach.

C++




// C++ program for the above approach
#include <bits/stdc++.h>
  
// Common file
#include <ext/pb_ds/assoc_container.hpp>
  
// Including tree_order_statistics_node_update
#include <ext/pb_ds/tree_policy.hpp>
  
using namespace std;
using namespace __gnu_pbds;
  
// Declaring ordered_set
typedef tree<int, null_type, less<int>,
             rb_tree_tag,
             tree_order_statistics_node_update>
    ordered_set;
  
// Map to store final ans for each node
unordered_map<int, int> ans;
  
// Function to add an edge
// between nodes u and v
void addEdge(vector<int> adj[],
             int u, int v)
{
    adj[u].push_back(v);
    adj[v].push_back(u);
}
  
// Function to count the number of
// ancestors with values smaller
// than that of the current node
void countSmallerAncestors(
    vector<int> adj[],
    int root, int par,
    ordered_set& ancestors)
{
  
    // Map current node to
    // number of smaller valued ancestors
    ans[root] = ancestors.order_of_key(root);
  
    // Add current node to path
    ancestors.insert(root);
    for (int node : adj[root]) {
  
        // Avoid cycles
        if (node != par) {
            countSmallerAncestors(
                adj, node,
                root, ancestors);
        }
    }
  
    // Remove current node from path
    ancestors.erase(root);
}
  
// Driver Code
int main()
{
    // Number of nodes in graph
    int N = 7;
  
    // Initialize graph
    vector<int> adj[N + 1];
  
    // Tree Formation
    addEdge(adj, 1, 5);
    addEdge(adj, 1, 4);
    addEdge(adj, 4, 6);
    addEdge(adj, 5, 3);
    addEdge(adj, 5, 2);
    addEdge(adj, 5, 7);
  
    // Ordered set to store values in path
    // from root to current node in dfs
    ordered_set ancestors;
  
    countSmallerAncestors(adj, 1, -1, ancestors);
  
    for (int i = 1; i <= N; i++) {
        cout << ans[i] << " ";
    }
  
    return 0;
}

Output:

0 1 1 1 1 2 2

Time Complexity: O(N * log(N)).
Auxiliary Space:  O(N).


My Personal Notes arrow_drop_up
Recommended Articles
Page :

Start Your Coding Journey Now!