Open In App

Queries for the number of nodes having values less than V in the subtree of a Node

Improve
Improve
Like Article
Like
Save
Share
Report

Given a rooted tree (assume root is 1) of N nodes and Q queries, each of the form (Val, Node). For each query, the task is to find the number of nodes with values smaller than Val in sub-tree of Node, including itself. 
Note that by definition, nodes in this tree are unique.
Examples: 
 

Input: N = 7, Q = 3
Val = 4, Node = 4
Val = 7, Node = 6
Val = 5, Node = 1
Given tree:

Output: 2
1
4
Explanation: For given queries:
Q1 -> Val = 4, Node = 4
The required nodes are 2 and 3
Hence the output is 2
Q2 -> Val = 7, Node = 6
The required node is 6 only
Hence the output is 1
Q3 -> Val = 5, Node = 1
The required nodes are 1, 2, 3 and 4
Hence the output is 4

Naive approach: A simple approach to solve this problem would be to run DFS from a given node for each query and count the number of nodes smaller than the given value. The parent of a given node must be excluded from the DFS. 
Time complexity: O(N*Q), where Q is the number of queries and N is the number of nodes in the tree. 
Efficient Approach: We can reduce the problem of finding the number of elements in a sub-tree to finding them in contiguous segments of an array. To generate such a representation we run a DFS from the root node and push the node into an array when we enter into it the first time and while exiting for the last time. This representation of a tree is known as Euler Tour of the tree. 
For example, 
 

The Euler Tour of the above tree will be: 
 

1 4 2 2 3 3 5 5 4 6 7 7 6 1

This representation of tree has the property that the sub-tree of every node X is contained within the first and last occurrence of X in the array. Each node appears exactly twice. So counting the number of nodes smaller than Val between the first and last occurrence of Node will give us twice the answer of that query. 
Using this representation, the queries can be processed offline in O(log(N)) per query using a binary indexed tree. 
Pre-processing: 
 

  1. We store the index of 1st and last occurrence of each node in the Tour in two arrays, start and end. Let start[X] and end[X] represent these indices for node X. This can be done in O(N)
  2. In the Euler Tour we store the position of the element along with node as a pair (indexInTree, indexInTour), and then sort according to indexInTree. Let this array be sortedTour
  3. Similarly, we maintain an array of Queries of the form (Val, Node) and sort according to Val. Let this array be sortedQuery
  4. Initialize a Binary Indexed Tree of size 2N with all entries as 0. Let this be bit
  5. Then proceed as follows. Maintain a pointer each in sortedTour and sortedQuery
  6. For each query in sortedQuery from the beginning select the nodes from sortedTour having indexInTree < Val, and increment their indexInTour in bit. Then the answer of that query would be half of the sum from start[Node] to end[Node]
  7. For the next query in sortedQuery we select any previously un-selected nodes from sortedTour having indexInTree < Val, and increment their indexInTour in bit and answer the query as done before.
  8. Repeating this process for each query we can answer them in O(Qlog(N)).

Below is the C++ implementation of the above approach: 
 

CPP




// C++ program Queries to find the Number of
// Nodes having Smaller Values from a Given
// Value in the Subtree of a Node
#include <bits/stdc++.h>
using namespace std;
   
// Takes a tree and generates a Euler tour for that
// tree in 'tour' parameter This is a modified form
// of DFS in which we push the node while entering for
// the first time and when exiting from it
void eulerTour(vector<vector<int> >& tree,
               vector<int>& vst,
               int root,
               vector<int>& tour)
{
   
    // Push node in tour while entering
    tour.push_back(root);
   
    // DFS
    vst[root] = 1;
    for (auto& x : tree[root]) {
        if (!vst[x]) {
            eulerTour(tree, vst, x, tour);
        }
    }
   
    // Push node in tour while exiting
    tour.push_back(root);
}
   
// Creates the start and end array as described in
// pre-processing section. Traverse the tour from
// left to right and update start for 1st occurrence
// and end for 2nd occurrence of each node
void createStartEnd(vector<int>& tour,
                    vector<int>& start,
                    vector<int>& end)
{
    for (int i = 1; i < tour.size(); ++i) {
        if (start[tour[i]] == -1) {
            start[tour[i]] = i;
        }
        else {
            end[tour[i]] = i;
        }
    }
}
   
// Returns a sorted array of pair containing node and
// tourIndex as described in pre-processing section
vector<pair<int, int> >
createSortedTour(vector<int>& tour)
{
    vector<pair<int, int> > arr;
    for (int i = 1; i < tour.size(); ++i) {
        arr.push_back(make_pair(tour[i], i));
    }
    sort(arr.begin(), arr.end());
    return arr;
}
   
// Binary Indexed Tree Implementation
// This function will add 1 from the position
void increment(vector<int>& bit, int pos)
{
    for (; pos < bit.size(); pos += pos & -pos) {
        bit[pos]++;
    }
}
   
// It will give the range sum
int query(vector<int>& bit,
              int start,
              int end)
{
    --start;
    int s1 = 0, s2 = 0;
    for (; start > 0; start -= start & -start) {
        s1 += bit[start];
    }
    for (; end > 0; end -= end & -end) {
        s2 += bit[end];
    }
    return s2 - s1;
}
  
// Function to calculate the ans for each query
map<pair<int, int>, int> cal(int N,
                                         int Q,
                      vector<vector<int>> tree,
            vector<pair<int, int>> queries)
{
    // Preprocessing
    // Creating the vector to store the tours and queries
    vector<int> tour, vst(N + 1, 0),
        start(N + 1, -1),
        end(N + 1, -1),
        bit(2 * N + 4, 0);
   
    // For one based indexing in tour.
    // Simplifies code for Binary Indexed Tree.
    // We will ignore the 1st element in tour
    tour.push_back(-1);
   
    // Create Euler Tour
    eulerTour(tree, vst, 1, tour);
   
    // Create Start and End Array
    createStartEnd(tour, start, end);
   
    // Create sortedTour and sortedQuery
    auto sortedTour = createSortedTour(tour);
   
    auto sortedQuery = queries;
   
    sort(sortedQuery.begin(), sortedQuery.end());
   
    // For storing answers to query
    map<pair<int, int>, int> queryAns;
   
    // We maintain pointers each for sortedTour and
    // sortedQuery.For each element X in sortedTour
    // we first process any queries with val smaller
    // than X's node and update queryptr to first
    // unprocessed query.Then update the position
    // of X in BIT.
   
    int tourptr = 0, queryptr = 0;
    while (queryptr < sortedQuery.size()) {
   
        // Queries lies in the range then
        while (queryptr < sortedQuery.size()
               && sortedQuery[queryptr].first
                      <= sortedTour[tourptr].first){
   
            auto node = sortedQuery[queryptr].second;
   
            // Making the query on BIT and dividing by 2.
            queryAns[sortedQuery[queryptr]]
                = query(bit, start[node], end[node]) / 2;
            ++queryptr;
        }
        if (tourptr < sortedTour.size()) {
            increment(bit, sortedTour[tourptr].second);
            ++tourptr;
        }
    }
  
    return queryAns;
}
  
// Driver Code
int main()
{
  
    int N = 7, Q = 3;
   
    // Tree edges
    vector<vector<int> > tree = { {},
                                      { 4, 6 },
                                      { 4 },
                                      { 4 },
                                      { 1, 2, 3, 5 },
                                      { 4 },
                                      { 1, 7 },
                                      { 6 } };
   
    // Queries vector
    vector<pair<int, int> > queries
        = { make_pair(4, 1),
            make_pair(7, 6),
            make_pair(5, 1) };
   
    // Calling the function
    map<pair<int, int>, int> queryAns =
                    cal(N, Q, tree, queries);
  
    // Print answer in order of input.
    for (auto& x : queries) {
        cout << queryAns[x] << '\n';
    }
   
    return 0;
}


Java




import java.util.*;
 
public class SubtreeQueries {
 
    // Takes a tree and generates an Euler tour for that tree in the 'tour' parameter
    // This is a modified form of DFS in which we push the node while entering for the first time and when exiting from it
    static void eulerTour(List<List<Integer>> tree, List<Integer> vst, int root, List<Integer> tour) {
        // Push node in tour while entering
        tour.add(root);
 
        // DFS
        vst.set(root, 1);
        for (int x : tree.get(root)) {
            if (vst.get(x) == 0) {
                eulerTour(tree, vst, x, tour);
            }
        }
 
        // Push node in tour while exiting
        tour.add(root);
    }
 
    // Creates the start and end array as described in the pre-processing section.
    // Traverse the tour from left to right and update start for the 1st occurrence and end for the 2nd occurrence of each node
    static void createStartEnd(List<Integer> tour, List<Integer> start, List<Integer> end) {
        for (int i = 1; i < tour.size(); ++i) {
            int node = tour.get(i);
            if (start.get(node) == -1) {
                start.set(node, i);
            } else {
                end.set(node, i);
            }
        }
    }
 
    // Returns a sorted array of pairs containing node and tourIndex as described in the pre-processing section
    static List<Pair<Integer, Integer>> createSortedTour(List<Integer> tour) {
        List<Pair<Integer, Integer>> arr = new ArrayList<>();
        for (int i = 1; i < tour.size(); ++i) {
            arr.add(new Pair<>(tour.get(i), i));
        }
        Collections.sort(arr, Comparator.comparingInt(Pair::getKey));
        return arr;
    }
 
    // Binary Indexed Tree Implementation
    // This function will add 1 from the position
    static void increment(List<Integer> bit, int pos) {
        for (; pos < bit.size(); pos += pos & -pos) {
            bit.set(pos, bit.get(pos) + 1);
        }
    }
 
    // It will give the range sum
    static int query(List<Integer> bit, int start, int end) {
        --start;
        int s1 = 0, s2 = 0;
        for (; start > 0; start -= start & -start) {
            s1 += bit.get(start);
        }
        for (; end > 0; end -= end & -end) {
            s2 += bit.get(end);
        }
        return s2 - s1;
    }
 
    // Function to calculate the answer for each query
    static Map<Pair<Integer, Integer>, Integer> cal(int N, int Q, List<List<Integer>> tree, List<Pair<Integer, Integer>> queries) {
        // Preprocessing
        // Creating the vector to store the tours and queries
        List<Integer> tour = new ArrayList<>();
        List<Integer> vst = new ArrayList<>(Collections.nCopies(N + 1, 0));
        List<Integer> start = new ArrayList<>(Collections.nCopies(N + 1, -1));
        List<Integer> end = new ArrayList<>(Collections.nCopies(N + 1, -1));
        List<Integer> bit = new ArrayList<>(Collections.nCopies(2 * N + 4, 0));
 
        // For one based indexing in tour.
        // Simplifies code for Binary Indexed Tree.
        // We will ignore the 1st element in tour
        tour.add(-1);
 
        // Create Euler Tour
        eulerTour(tree, vst, 1, tour);
 
        // Create Start and End Array
        createStartEnd(tour, start, end);
 
        // Create sortedTour and sortedQuery
        List<Pair<Integer, Integer>> sortedTour = createSortedTour(tour);
        List<Pair<Integer, Integer>> sortedQuery = new ArrayList<>(queries);
        sortedQuery.sort(Comparator.comparingInt(Pair::getKey));
 
        // For storing answers to queries
        Map<Pair<Integer, Integer>, Integer> queryAns = new LinkedHashMap<>();
 
        // We maintain pointers each for sortedTour and sortedQuery.
        // For each element X in sortedTour, we first process any queries with val smaller
        // than X's node and update queryptr to the first unprocessed query.
        // Then update the position of X in BIT.
        int tourptr = 0, queryptr = 0;
        while (queryptr < sortedQuery.size()) {
            // Queries lie in the range then
            while (queryptr < sortedQuery.size() && sortedQuery.get(queryptr).getKey() <= sortedTour.get(tourptr).getKey()) {
                int node = sortedQuery.get(queryptr).getValue();
 
                // Making the query on BIT and dividing by 2.
                queryAns.put(sortedQuery.get(queryptr), query(bit, start.get(node), end.get(node)) / 2);
                ++queryptr;
            }
            if (tourptr < sortedTour.size()) {
                increment(bit, sortedTour.get(tourptr).getValue());
                ++tourptr;
            }
        }
 
        return queryAns;
    }
 
    // Driver Code
    public static void main(String[] args) {
        int N = 7, Q = 3;
 
        // Tree edges
        List<List<Integer>> tree = Arrays.asList(
                Collections.emptyList(),
                Arrays.asList(4, 6),
                Collections.singletonList(4),
                Collections.singletonList(4),
                Arrays.asList(1, 2, 3, 5),
                Collections.singletonList(4),
                Arrays.asList(1, 7),
                Collections.singletonList(6)
        );
 
        // Queries list
        List<Pair<Integer, Integer>> queries = Arrays.asList(
                new Pair<>(4, 1),
                new Pair<>(7, 6),
                new Pair<>(5, 1)
        );
 
        // Calling the function
        Map<Pair<Integer, Integer>, Integer> queryAns = cal(N, Q, tree, queries);
 
        // Print answer in the order of input
        for (Pair<Integer, Integer> x : queries) {
            System.out.println(queryAns.get(x));
        }
    }
}
 
// Pair class with generic Key and Value
class Pair<K, V> {
    private K key;
    private V value;
 
    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }
 
    public K getKey() {
        return key;
    }
 
    public V getValue() {
        return value;
    }
}


C#




using System;
using System.Collections.Generic;
using System.Linq;
 
class Program
{
    // Takes a tree and generates an Euler tour for that
    // tree in the 'tour' parameter. This is a modified form
    // of DFS in which we push the node while entering for
    // the first time and when exiting from it.
    static void EulerTour(List<List<int>> tree, List<int> vst, int root, List<int> tour)
    {
        // Push node in tour while entering
        tour.Add(root);
 
        // DFS
        vst[root] = 1;
        foreach (var x in tree[root])
        {
            if (vst[x] == 0)
            {
                EulerTour(tree, vst, x, tour);
            }
        }
 
        // Push node in tour while exiting
        tour.Add(root);
    }
 
    // Creates the start and end array as described in
    // the pre-processing section. Traverse the tour from
    // left to right and update start for the 1st occurrence
    // and end for the 2nd occurrence of each node.
    static void CreateStartEnd(List<int> tour, List<int> start, List<int> end)
    {
        for (int i = 1; i < tour.Count; ++i)
        {
            if (start[tour[i]] == -1)
            {
                start[tour[i]] = i;
            }
            else
            {
                end[tour[i]] = i;
            }
        }
    }
 
    // Returns a sorted array of pairs containing node and
    // tourIndex as described in the pre-processing section.
    static List<Tuple<int, int>> CreateSortedTour(List<int> tour)
    {
        List<Tuple<int, int>> arr = new List<Tuple<int, int>>();
        for (int i = 1; i < tour.Count; ++i)
        {
            arr.Add(new Tuple<int, int>(tour[i], i));
        }
        arr.Sort();
        return arr;
    }
 
    // Binary Indexed Tree Implementation
    // This function will add 1 from the position
    static void Increment(List<int> bit, int pos)
    {
        for (; pos < bit.Count; pos += pos & -pos)
        {
            bit[pos]++;
        }
    }
 
    // It will give the range sum
    static int Query(List<int> bit, int start, int end)
    {
        --start;
        int s1 = 0, s2 = 0;
        for (; start > 0; start -= start & -start)
        {
            s1 += bit[start];
        }
        for (; end > 0; end -= end & -end)
        {
            s2 += bit[end];
        }
        return s2 - s1;
    }
 
    // Function to calculate the ans for each query
    static Dictionary<Tuple<int, int>, int> Cal(int N, int Q,
                                                List<List<int>> tree,
                                                List<Tuple<int,
                                                int>> queries)
    {
        // Preprocessing
        // Creating the vector to store the tours and queries
        List<int> tour = new List<int>();
        List<int> vst = Enumerable.Repeat(0, N + 1).ToList();
        List<int> start = Enumerable.Repeat(-1, N + 1).ToList();
        List<int> end = Enumerable.Repeat(-1, N + 1).ToList();
        List<int> bit = Enumerable.Repeat(0, 2 * N + 4).ToList();
 
        // For one-based indexing in tour.
        // Simplifies code for Binary Indexed Tree.
        // We will ignore the 1st element in the tour
        tour.Add(-1);
 
        // Create Euler Tour
        EulerTour(tree, vst, 1, tour);
 
        // Create Start and End Array
        CreateStartEnd(tour, start, end);
 
        // Create sortedTour and sortedQuery
        var sortedTour = CreateSortedTour(tour);
        var sortedQuery = queries.ToList();
 
        sortedQuery.Sort();
 
        // For storing answers to the query
        Dictionary<Tuple<int, int>, int> queryAns = new Dictionary<Tuple<int, int>, int>();
 
        // We maintain pointers each for sortedTour and
        // sortedQuery. For each element X in sortedTour,
        // we first process any queries with val smaller
        // than X's node and update queryptr to the first
        // unprocessed query. Then update the position
        // of X in BIT.
 
        int tourptr = 0, queryptr = 0;
        while (queryptr < sortedQuery.Count)
        {
            // Queries lie in the range then
            while (queryptr < sortedQuery.Count &&
                sortedQuery[queryptr].Item1 <= sortedTour[tourptr].Item1)
            {
                var node = sortedQuery[queryptr].Item2;
 
                // Making the query on BIT and dividing by 2.
                queryAns[sortedQuery[queryptr]] = Query(bit, start[node], end[node]) / 2;
                ++queryptr;
            }
            if (tourptr < sortedTour.Count)
            {
                Increment(bit, sortedTour[tourptr].Item2);
                ++tourptr;
            }
        }
 
        return queryAns;
    }
 
    // Driver Code
    static void Main()
    {
        int N = 7, Q = 3;
 
        // Tree edges
        List<List<int>> tree = new List<List<int>> {
            new List<int>(),
            new List<int> { 4, 6 },
            new List<int> { 4 },
            new List<int> { 4 },
            new List<int> { 1, 2, 3, 5 },
            new List<int> { 4 },
            new List<int> { 1, 7 },
            new List<int> { 6 }
        };
 
        // Queries vector
        List<Tuple<int, int>> queries = new List<Tuple<int, int>> {
            new Tuple<int, int>(4, 1),
            new Tuple<int, int>(7, 6),
            new Tuple<int, int>(5, 1)
        };
 
        // Calling the function
        Dictionary<Tuple<int, int>, int> queryAns = Cal(N, Q, tree, queries);
 
        // Print answer in the order of input.
        foreach (var x in queries)
        {
            Console.WriteLine(queryAns[x]);
        }
    }
}


Javascript




// Takes a tree and generates a Euler tour for that
// tree in 'tour' parameter This is a modified form
// of DFS in which we push the node while entering for
// the first time and when exiting from it
function eulerTour(tree, vst, root, tour) {
    // Push node in tour while entering
    tour.push(root);
 
    // DFS
    vst[root] = 1;
    for (let x of tree[root]) {
        if (!vst[x]) {
            eulerTour(tree, vst, x, tour);
        }
    }
 
    // Push node in tour while exiting
    tour.push(root);
}
 
// Creates the start and end array as described in
// pre-processing section. Traverse the tour from
// left to right and update start for 1st occurrence
// and end for 2nd occurrence of each node
function createStartEnd(tour, start, end) {
    for (let i = 1; i < tour.length; ++i) {
        if (start[tour[i]] === -1) {
            start[tour[i]] = i;
        } else {
            end[tour[i]] = i;
        }
    }
}
 
// Returns a sorted array of pair containing node and
// tourIndex as described in pre-processing section
function createSortedTour(tour) {
    let arr = [];
    for (let i = 1; i < tour.length; ++i) {
        arr.push([tour[i], i]);
    }
    arr.sort((a, b) => a[0] - b[0]);
    return arr;
}
 
// Binary Indexed Tree Implementation
// This function will add 1 from the position
function increment(bit, pos) {
    for (; pos < bit.length; pos += pos & -pos) {
        bit[pos]++;
    }
}
 
// It will give the range sum
function query(bit, start, end) {
    --start;
    let s1 = 0, s2 = 0;
    for (; start > 0; start -= start & -start) {
        s1 += bit[start];
    }
    for (; end > 0; end -= end & -end) {
        s2 += bit[end];
    }
    return s2 - s1;
}
 
// Function to calculate the ans for each query
function cal(N, Q, tree, queries) {
    // Preprocessing
    // Creating the vector to store the tours and queries
    let tour = [],
        vst = Array(N + 1).fill(0),
        start = Array(N + 1).fill(-1),
        end = Array(N + 1).fill(-1),
        bit = Array(2 * N + 4).fill(0);
 
    // For one based indexing in tour.
    // Simplifies code for Binary Indexed Tree.
    // We will ignore the 1st element in tour
    tour.push(-1);
 
    // Create Euler Tour
    eulerTour(tree, vst, 1, tour);
 
    // Create Start and End Array
    createStartEnd(tour, start, end);
 
    // Create sortedTour and sortedQuery
    let sortedTour = createSortedTour(tour);
    let sortedQuery = [...queries].sort((a, b) => a[0] - b[0]);
 
    // For storing answers to query
    let queryAns = new Map();
 
    // We maintain pointers each for sortedTour and
    // sortedQuery.For each element X in sortedTour
    // we first process any queries with val smaller
    // than X's node and update queryptr to first
    // unprocessed query.Then update the position
    // of X in BIT.
 
    let tourptr = 0,
        queryptr = 0;
    while (queryptr < sortedQuery.length) {
        // Queries lies in the range then
        while (
            queryptr < sortedQuery.length &&
            sortedQuery[queryptr][0] <= sortedTour[tourptr][0]
        ) {
            let node = sortedQuery[queryptr][1];
 
            // Making the query on BIT and dividing by 2.
            queryAns.set(sortedQuery[queryptr], query(bit, start[node], end[node]) / 2);
            ++queryptr;
        }
        if (tourptr < sortedTour.length) {
            increment(bit, sortedTour[tourptr][1]);
            ++tourptr;
        }
    }
 
    return queryAns;
}
 
// Driver Code
function main() {
    let N = 7,
        Q = 3;
 
    // Tree edges
    let tree = [
        [],
        [4, 6],
        [4],
        [4],
        [1, 2, 3, 5],
        [4],
        [1, 7],
        [6],
    ];
 
    // Queries vector
    let queries = [
        [4, 1],
        [7, 6],
        [5, 1],
    ];
 
    // Calling the function
    let queryAns = cal(N, Q, tree, queries);
 
    // Print answer in order of input.
    for (let x of queries) {
        console.log(queryAns.get(x));
    }
}
 
main();


Python3




# Python3 implementation for the above approach
 
# Import necessary libraries
from typing import List, Tuple, Dict
from collections import defaultdict
 
# Recursive function to perform euler tour on the tree
def eulerTour(tree: List[List[int]], vst: List[int], root: int, tour: List[int]) -> None:
   
    # Append the root to the tour
    tour.append(root)
     
    # Mark the root as visited
    vst[root] = 1
     
    # Traverse through all the children of the root
    for x in tree[root]:
       
        # If a child is not visited,
        # perform euler tour on that child
        if not vst[x]:
            eulerTour(tree, vst, x, tour)
             
    # Append the root again to
    # complete the cycle of euler tour
    tour.append(root)
 
# Create start and end index for each node in the euler tour
def createStartEnd(tour: List[int], start: List[int], end: List[int]) -> None:
   
    # Traverse through the euler tour and
    # store the start and end index for each node
    for i in range(1, len(tour)):
       
        if start[tour[i]] == -1:
            start[tour[i]] = i
        else:
            end[tour[i]] = i
             
# Create a sorted euler tour
def createSortedTour(tour: List[int]) -> List[Tuple[int, int]]:
   
    # Create a tuple with the node and its index in the euler tour
    arr = [(tour[i], i) for i in range(1, len(tour))]
     
    # Sort the array of tuples by the node values
    arr.sort()
     
    # Return the sorted array of tuples
    return arr
     
# Increment the value of a position in the binary indexed tree
def increment(bit: List[int], pos: int) -> None:
   
    # Traverse through the binary indexed tree and increment
    # the value at the given position and its ancestors
    while pos < len(bit):
        bit[pos] += 1
        pos += pos & -pos
 
 
def query(bit: List[int], start: int, end: int) -> int:
   
    # Subtract 1 from start position as indexing starts from 0
    start -= 1
    s1, s2 = 0, 0
     
    # Calculate sum of BIT from start to root of the tree
    while start > 0:
        s1 += bit[start]
        start -= start & -start
         
    # Calculate sum of BIT from end to root of the tree
    while end > 0:
        s2 += bit[end]
        end -= end & -end
         
    # Return the difference between s2 and s1
    return s2 - s1
 
def cal(N: int, Q: int, tree: List[List[int]],
        queries: List[Tuple[int, int]]) -> Dict[Tuple[int, int], int]:
   
    # Initialize variables
    tour, vst, start, end, bit = [-1], [0]*(N+1), [-1]*(N+1), [-1]*(N+1), [0]*(2*N+4)
     
    # Perform Euler tour to create the tour list
    eulerTour(tree, vst, 1, tour)
     
    # Create start and end arrays
    createStartEnd(tour, start, end)
     
    # Sort the tour list based on node values
    sortedTour = createSortedTour(tour)
     
    # Sort the queries list
    sortedQuery = sorted(queries)
     
    # Initialize a defaultdict to store the query results
    queryAns = defaultdict(int)
     
    # Initialize pointers
    tourptr, queryptr = 0, 0
     
    # Iterate through sortedQuery list
    while queryptr < len(sortedQuery):
       
        # Iterate through queries whose node values are
        # less than or equal to the current tour node
        while queryptr < len(sortedQuery) and sortedQuery[queryptr][0] <= sortedTour[tourptr][0]:
           
            # Get the node value from the current query
            node = sortedQuery[queryptr][1]
             
            # Calculate and store the query result in queryAns dictionary
            queryAns[sortedQuery[queryptr]] = query(bit, start[node], end[node]) // 2
             
            # Increment the query pointer
            queryptr += 1
             
        # Increment BIT at the position
        # corresponding to the current tour node
        if tourptr < len(sortedTour):
            increment(bit, sortedTour[tourptr][1])
             
            # Increment the tour pointer
            tourptr += 1
     
    # Return the queryAns dictionary
    return queryAns
 
 
# Driver Code
if __name__ == "__main__":
    import math
   
    N = 7
    Q = 3
   
    # Tree edges
    tree = { 1: [4, 6],
             2: [4],
             3: [4],
             4: [1, 2, 3, 5],
             5: [4],
             6: [1, 7],
             7: [6] }
   
    # Queries vector
    queries = [(4, 1), (7, 6), (5, 1)]
   
    # Calling the function
    queryAns = cal(N, Q, tree, queries)
  
    # Print answer in order of input.
    for query in queries:
        print(queryAns[query])
 
# This code is contributed by amit_mangal_


Output

3
1
4

Auxiliary Space: O(Q+N*log(N))



Last Updated : 11 Mar, 2024
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads