Open In App

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

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.

Below is the implementation of the above approach.




// 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;
}




//Java program for the above approach
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
 
class ordered_set implements Comparable<Integer> {
    Set<Integer> tree;
    public ordered_set() {
        tree = new TreeSet<>();
    }
 
    public void insert(int val) {
        tree.add(val);
    }
 
    public int order_of_key(int val) {
        int count = 0;
        for (Integer integer : tree) {
            if (integer < val) {
                count++;
            }
        }
        return count;
    }
 
    public void erase(int val) {
        tree.remove(val);
    }
 
    @Override
    public int compareTo(Integer o) {
        return Integer.compare(this.order_of_key(o), o);
    }
}
 
class Main {
    static Map<Integer, List<Integer>> adj = new HashMap<>();
    static Map<Integer, Integer> ans = new HashMap<>();
    static void addEdge(int u, int v) {
        adj.computeIfAbsent(u, k -> new LinkedList<>()).add(v);
        adj.computeIfAbsent(v, k -> new LinkedList<>()).add(u);
    }
    static void countSmallerAncestors(int root, int par, ordered_set ancestors) {
        ans.put(root, ancestors.order_of_key(root));
        ancestors.insert(root);
        for (Integer node : adj.get(root)) {
            if (node != par) {
                countSmallerAncestors(node, root, ancestors);
            }
        }
        ancestors.erase(root);
    }
 
    public static void main(String[] args) {
        int N = 7;
        addEdge(1, 5);
        addEdge(1, 4);
        addEdge(4, 6);
        addEdge(5, 3);
        addEdge(5, 2);
        addEdge(5, 7);
        ordered_set ancestors = new ordered_set();
        countSmallerAncestors(1, -1, ancestors);
 
        for (int i = 1; i <= N; i++) {
            System.out.print(ans.get(i) + " ");
        }
    }
}
 
//This code is contributed by shivamsharma215




# Python program for the above approach
import collections
import functools
 
# Declaring ordered_set
@functools.total_ordering
class ordered_set:
    def __init__(self):
        self.tree = collections.defaultdict(set)
 
    def insert(self, val):
        self.tree[val] = set()
 
    def __le__(self, other):
        return self.tree.keys() <= other.tree.keys()
 
    def __eq__(self, other):
        return self.tree.keys() == other.tree.keys()
 
    def order_of_key(self, val):
        return len([k for k in self.tree.keys() if k < val])
 
    def erase(self, val):
        del self.tree[val]
 
# Map to store final ans for each node
ans = {}
 
# Function to add an edge
# between nodes u and v
def addEdge(adj, u, v):
    adj[u].append(v)
    adj[v].append(u)
 
# Function to count the number of
# ancestors with values smaller
# than that of the current node
def countSmallerAncestors(adj, root, par, 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 node in adj[root]:
        # Avoid cycles
        if node != par:
            countSmallerAncestors(
                adj, node,
                root, ancestors)
 
    # Remove current node from path
    ancestors.erase(root)
 
# Driver Code
if __name__ == '__main__':
    # Number of nodes in graph
    N = 7
 
    # Initialize graph
    adj = {i:[] for i in range(1,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
    ancestors = ordered_set()
 
    countSmallerAncestors(adj, 1, -1, ancestors)
 
    for i in range(1, N+1):
        print(ans[i], end=' ')
 
# # This code is contributed by Vikram_Shirsat




const adj = [];
const ans = new Map();
 
// Function to add an edge between nodes u and v
function addEdge(u, v) {
    adj[u].push(v);
    adj[v].push(u);
}
 
// Function to count the number of ancestors with values smaller
// than that of the current node
function countSmallerAncestors(root, par, ancestors) {
    // Map current node to number of smaller valued ancestors
    ans.set(root, ancestors.indexOf(root));
 
    // Add current node to path
    ancestors.push(root);
    for (const node of adj[root]) {
        // Avoid cycles
        if (node !== par) {
            countSmallerAncestors(node, root, ancestors);
        }
    }
 
    // Remove current node from path
    ancestors.pop();
}
 
// Main
(function() {
    // Number of nodes in graph
    const N = 7;
 
    // Initialize graph
    for (let i = 0; i <= N; i++) {
        adj[i] = [];
    }
 
    // Tree Formation
    addEdge(1, 5);
    addEdge(1, 4);
    addEdge(4, 6);
    addEdge(5, 3);
    addEdge(5, 2);
    addEdge(5, 7);
 
    // Array to store values in path from root to current node in dfs
    const ancestors = [];
 
    countSmallerAncestors(1, -1, ancestors);
 
    for (let i = 1; i <= N; i++) {
        console.log(ans.get(i));
    }
})();




using System;
using System.Collections.Generic;
 
// Declaring ordered_set
public class OrderedSet
{
    private Dictionary<int, HashSet<int>> tree = new Dictionary<int, HashSet<int>>();
 
    public void Insert(int val)
    {
        tree[val] = new HashSet<int>();
    }
 
    public bool IsSubsetOf(OrderedSet other)
    {
        return new HashSet<int>(tree.Keys).IsSubsetOf(other.tree.Keys);
    }
 
    public int CountSmaller(int val)
    {
        int count = 0;
        foreach (int k in tree.Keys)
        {
            if (k < val)
            {
                count++;
            }
        }
        return count;
    }
 
    public void Erase(int val)
    {
        tree.Remove(val);
    }
}
 
public class Program
{
    // Map to store final ans for each node
    private static Dictionary<int, int> ans = new Dictionary<int, int>();
 
    // Function to add an edge
    // between nodes u and v
    private static void AddEdge(Dictionary<int, List<int>> adj, int u, int v)
    {
        adj[u].Add(v);
        adj[v].Add(u);
    }
 
    // Function to count the number of
    // ancestors with values smaller
    // than that of the current node
    private static void CountSmallerAncestors(Dictionary<int, List<int>> adj, int root, int par, OrderedSet ancestors)
    {
        // Map current node to
        // number of smaller valued ancestors
        ans[root] = ancestors.CountSmaller(root);
 
        // Add current node to path
        ancestors.Insert(root);
        foreach (int node in adj[root])
        {
            // Avoid cycles
            if (node != par)
            {
                CountSmallerAncestors(adj, node, root, ancestors);
            }
        }
 
        // Remove current node from path
        ancestors.Erase(root);
    }
 
    // Driver Code
    public static void Main()
    {
        // Number of nodes in graph
        int N = 7;
 
        // Initialize graph
        Dictionary<int, List<int>> adj = new Dictionary<int, List<int>>();
        for (int i = 1; i <= N; i++)
        {
            adj[i] = new List<int>();
        }
 
        // 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
        OrderedSet ancestors = new OrderedSet();
 
        CountSmallerAncestors(adj, 1, -1, ancestors);
 
        for (int i = 1; i <= N; i++)
        {
            Console.Write(ans[i] + " ");
        }
    }
}

Output:
0 1 1 1 1 2 2

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


Article Tags :