Given an N-ary Tree consisting of N nodes valued from 1 to N, an array arr[] consisting of N positive integers, where arr[i] is the value associated with the ith node, and Q queries, each consisting of a node. The task for each query is to find the Bitwise OR of node values present in the subtree of the given node.
Examples:
Input: arr[] = {2, 3, 4, 8, 16} Queries[]: {2, 3, 1}
Output: 3 28 31
Explanation:
Query 1: Bitwise OR(subtree(Node 2)) = Bitwise OR(Node 2) = Bitwise OR(3) = 3
Query 2: Bitwise OR(subtree(Node 3)) = Bitwise OR(Node 3, Node 4, Node 5) = Bitwise OR(4, 8, 16) = 28
Query 3: Bitwise OR(subtree(Node 1)) = Bitwise OR(Node1, Node 2, Node 3, Node 4, Node 5) = Bitwise OR(2, 3, 4, 8, 16) = 31Input: arr[] = {2, 3, 4, 8, 16} Queries[]: {4, 5}
Output: 8 16
Explanation:
Query 1: Bitwise OR(subtree(Node 4)) = bitwise OR(Node 4) = 8
Query 2: Bitwise OR(subtree(Node 5)) = bitwise OR(Node 5) = 16
Naive Approach: The simplest approach to solve this problem is to traverse the subtree of the given node and for each query, calculate the Bitwise OR of every node in the subtree of that node and print that value.
Time Complexity: O(Q * N)
Auxiliary Space: O(Q * N)
Efficient Approach: To optimize the above approach, the idea is to precompute the Bitwise OR of all subtrees present in the given tree, and for each query, find the Bitwise XOR of subtrees for every given node. Follow the steps below to solve the problem:
- Initialize a vector ans[] to store the Bitwise OR of all subtrees present in the given Tree.
- Precompute the Bitwise OR for every subtree using Depth First Search(DFS).
- If the node is a leaf node, the bitwise OR of this node is the node value itself.
- Otherwise, the Bitwise OR for the subtree is equal to the Bitwise OR of all subtree values of its children.
- After completing the above steps, print the value stored at ans[Queries[i]] for every ith query.
Below is the implementation of the above approach:
// C++ program for the above approach #include <bits/stdc++.h> using namespace std;
// Maximum Number of nodes const int N = 1e5 + 5;
// Adjacency list vector< int > adj[N];
// Stores Bitwise OR of each node vector< int > answer(N);
// Function to add edges to the Tree void addEdgesToGraph( int Edges[][2],
int N)
{ // Traverse the edges
for ( int i = 0; i < N - 1; i++) {
int u = Edges[i][0];
int v = Edges[i][1];
// Add edges
adj[u].push_back(v);
adj[v].push_back(u);
}
} // Function to perform DFS // Traversal on the given tree void DFS( int node, int parent, int Val[])
{ // Initialize answer with bitwise
// OR of current node
answer[node] = Val[node];
// Iterate over each child
// of the current node
for ( int child : adj[node]) {
// Skip parent node
if (child == parent)
continue ;
// Call DFS for each child
DFS(child, node, Val);
// Taking bitwise OR of the
// answer of the child to
// find node's OR value
answer[node] = (answer[node]
| answer[child]);
}
} // Function to call DFS from the'= // root for precomputing answers void preprocess( int Val[])
{ DFS(1, -1, Val);
} // Function to calculate and print // the Bitwise OR for Q queries void findSubtreeOR( int Queries[], int Q,
int Val[])
{ // Perform preprocessing
preprocess(Val);
// Iterate over each given query
for ( int i = 0; i < Q; i++) {
cout << answer[Queries[i]]
<< ' ' ;
}
} // Utility function to find and // print bitwise OR for Q queries void findSubtreeORUtil(
int N, int Edges[][2], int Val[],
int Queries[], int Q)
{ // Function to add edges to graph
addEdgesToGraph(Edges, N);
// Function call
findSubtreeOR(Queries, Q, Val);
} // Driver Code int main()
{ // Number of nodes
int N = 5;
int Edges[][2]
= { { 1, 2 }, { 1, 3 },
{ 3, 4 }, { 3, 5 } };
int Val[] = { 0, 2, 3, 4, 8, 16 };
int Queries[] = { 2, 3, 1 };
int Q = sizeof (Queries)
/ sizeof (Queries[0]);
// Function call
findSubtreeORUtil(N, Edges, Val,
Queries, Q);
return 0;
} |
// Java program for above approach import java.util.*;
import java.lang.*;
import java.io.*;
class GFG
{ // Maximum Number of nodes
static int N = ( int )1e5 + 5 ;
// Adjacency list
static ArrayList<ArrayList<Integer>> adj;
// Stores Bitwise OR of each node
static int [] answer;
// Function to add edges to the Tree
static void addEdgesToGraph( int Edges[][],
int N)
{
// Traverse the edges
for ( int i = 0 ; i < N - 1 ; i++)
{
int u = Edges[i][ 0 ];
int v = Edges[i][ 1 ];
// Add edges
adj.get(u).add(v);
adj.get(v).add(u);
}
}
// Function to perform DFS
// Traversal on the given tree
static void DFS( int node, int parent, int Val[])
{
// Initialize answer with bitwise
// OR of current node
answer[node] = Val[node];
// Iterate over each child
// of the current node
for (Integer child : adj.get(node))
{
// Skip parent node
if (child == parent)
continue ;
// Call DFS for each child
DFS(child, node, Val);
// Taking bitwise OR of the
// answer of the child to
// find node's OR value
answer[node] = (answer[node]
| answer[child]);
}
}
// Function to call DFS from the'=
// root for precomputing answers
static void preprocess( int Val[])
{
DFS( 1 , - 1 , Val);
}
// Function to calculate and print
// the Bitwise OR for Q queries
static void findSubtreeOR( int Queries[], int Q,
int Val[])
{
// Perform preprocessing
preprocess(Val);
// Iterate over each given query
for ( int i = 0 ; i < Q; i++)
{
System.out.println(answer[Queries[i]] + " " );
}
}
// Utility function to find and
// print bitwise OR for Q queries
static void findSubtreeORUtil( int N, int Edges[][],
int Val[], int Queries[],
int Q)
{
// Function to add edges to graph
addEdgesToGraph(Edges, N);
// Function call
findSubtreeOR(Queries, Q, Val);
}
// Driver function
public static void main (String[] args)
{
adj = new ArrayList<>();
for ( int i = 0 ; i < N; i++)
adj.add( new ArrayList<>());
answer = new int [N];
N = 5 ;
int Edges[][] = { { 1 , 2 }, { 1 , 3 },
{ 3 , 4 }, { 3 , 5 } };
int Val[] = { 0 , 2 , 3 , 4 , 8 , 16 };
int Queries[] = { 2 , 3 , 1 };
int Q = Queries.length;
// Function call
findSubtreeORUtil(N, Edges, Val,
Queries, Q);
}
} // This code is contributed by offbeat |
# Python3 program for the above approach # Maximum Number of nodes N = 100005 ;
# Adjacency list adj = [[] for i in range (N)];
# Stores Bitwise OR of each node answer = [ 0 for i in range (N)]
# Function to add edges to the Tree def addEdgesToGraph(Edges, N):
# Traverse the edges
for i in range (N - 1 ):
u = Edges[i][ 0 ];
v = Edges[i][ 1 ];
# Add edges
adj[u].append(v);
adj[v].append(u);
# Function to perform DFS # Traversal on the given tree def DFS(node, parent, Val):
# Initialize answer with bitwise
# OR of current node
answer[node] = Val[node];
# Iterate over each child
# of the current node
for child in adj[node]:
# Skip parent node
if (child = = parent):
continue ;
# Call DFS for each child
DFS(child, node, Val);
# Taking bitwise OR of the
# answer of the child to
# find node's OR value
answer[node] = (answer[node]
| answer[child]);
# Function to call DFS from the'= # root for precomputing answers def preprocess( Val):
DFS( 1 , - 1 , Val);
# Function to calculate and print # the Bitwise OR for Q queries def findSubtreeOR(Queries, Q, Val):
# Perform preprocessing
preprocess(Val);
# Iterate over each given query
for i in range (Q):
print (answer[Queries[i]], end = ' ' )
# Utility function to find and # print bitwise OR for Q queries def findSubtreeORUtil( N, Edges, Val, Queries, Q):
# Function to add edges to graph
addEdgesToGraph(Edges, N);
# Function call
findSubtreeOR(Queries, Q, Val);
# Driver Code if __name__ = = '__main__' :
# Number of nodes
N = 5 ;
Edges = [ [ 1 , 2 ], [ 1 , 3 ], [ 3 , 4 ], [ 3 , 5 ] ];
Val = [ 0 , 2 , 3 , 4 , 8 , 16 ];
Queries = [ 2 , 3 , 1 ];
Q = len (Queries)
# Function call
findSubtreeORUtil(N, Edges, Val,Queries, Q);
# This code is contributed by rutvik_56
|
// C# program to generate // n-bit Gray codes using System;
using System.Collections.Generic;
class GFG
{ // Maximum Number of nodes
static int N = ( int )1e5 + 5;
// Adjacency list
static List<List< int > > adj;
// Stores Bitwise OR of each node
static int [] answer;
// Function to Add edges to the Tree
static void AddEdgesToGraph( int [, ] Edges, int N)
{
// Traverse the edges
for ( int i = 0; i < N - 1; i++) {
int u = Edges[i, 0];
int v = Edges[i, 1];
// Add edges
adj[u].Add(v);
adj[v].Add(u);
}
}
// Function to perform DFS
// Traversal on the given tree
static void DFS( int node, int parent, int [] Val)
{
// Initialize answer with bitwise
// OR of current node
answer[node] = Val[node];
// Iterate over each child
// of the current node
foreach ( int child in adj[node])
{
// Skip parent node
if (child == parent)
continue ;
// Call DFS for each child
DFS(child, node, Val);
// Taking bitwise OR of the
// answer of the child to
// find node's OR value
answer[node] = (answer[node] | answer[child]);
}
}
// Function to call DFS from the'=
// root for precomputing answers
static void preprocess( int [] Val) { DFS(1, -1, Val); }
// Function to calculate and print
// the Bitwise OR for Q queries
static void findSubtreeOR( int [] Queries, int Q,
int [] Val)
{
// Perform preprocessing
preprocess(Val);
// Iterate over each given query
for ( int i = 0; i < Q; i++) {
Console.Write(answer[Queries[i]] + " " );
}
}
// Utility function to find and
// print bitwise OR for Q queries
static void findSubtreeORUtil( int N, int [, ] Edges,
int [] Val, int [] Queries,
int Q)
{
// Function to Add edges to graph
AddEdgesToGraph(Edges, N);
// Function call
findSubtreeOR(Queries, Q, Val);
}
// Driver function
public static void Main(String[] args)
{
adj = new List<List< int > >();
for ( int i = 0; i < N; i++)
adj.Add( new List< int >());
answer = new int [N];
N = 5;
int [, ] Edges
= { { 1, 2 }, { 1, 3 }, { 3, 4 }, { 3, 5 } };
int [] Val = { 0, 2, 3, 4, 8, 16 };
int [] Queries = { 2, 3, 1 };
int Q = Queries.Length;
// Function call
findSubtreeORUtil(N, Edges, Val, Queries, Q);
}
} // This code is contributed by grand_master. |
<script> // Javascript program for the above approach // Maximum Number of nodes const N = 1e5 + 5; // Adjacency list let adj = []; for (let i = 0; i < N; i++) {
adj.push([])
} // Stores Bitwise OR of each node let answer = new Array(N);
// Function to add edges to the Tree function addEdgesToGraph(Edges, N) {
// Traverse the edges
for (let i = 0; i < N - 1; i++) {
let u = Edges[i][0];
let v = Edges[i][1];
// Add edges
adj[u].push(v);
adj[v].push(u);
}
} // Function to perform DFS // Traversal on the given tree function DFS(node, parent, Val) {
// Initialize answer with bitwise
// OR of current node
answer[node] = Val[node];
// Iterate over each child
// of the current node
for (let child of adj[node]) {
// Skip parent node
if (child == parent)
continue ;
// Call DFS for each child
DFS(child, node, Val);
// Taking bitwise OR of the
// answer of the child to
// find node's OR value
answer[node] = (answer[node] | answer[child]);
}
} // Function to call DFS from the'= // root for precomputing answers function preprocess(Val) {
DFS(1, -1, Val);
} // Function to calculate and print // the Bitwise OR for Q queries function findSubtreeOR(Queries, Q, Val) {
// Perform preprocessing
preprocess(Val);
// Iterate over each given query
for (let i = 0; i < Q; i++) {
document.write(answer[Queries[i]] + ' ' );
}
} // Utility function to find and // print bitwise OR for Q queries function findSubtreeORUtil(N, Edges, Val, Queries, Q) {
// Function to add edges to graph
addEdgesToGraph(Edges, N);
// Function call
findSubtreeOR(Queries, Q, Val);
} // Driver Code // Number of nodes let n = 5; let Edges = [[1, 2], [1, 3],
[3, 4], [3, 5]];
let Val = [0, 2, 3, 4, 8, 16]; let Queries = [2, 3, 1]; let Q = Queries.length; // Function call findSubtreeORUtil(n, Edges, Val, Queries, Q); // This code is contributed by _saurabh_jaiswal </script> |
3 28 31
Time Complexity: O(N + Q)
Auxiliary Space: O(N)