Open In App

Find edge to be deleted from Tree to maximise product of XOR of components

Improve
Improve
Like Article
Like
Save
Share
Report

Given a tree of having N nodes rooted at node 0, and an array val[] denoting the value at each node, the task is to find the maximum possible product of XOR of connected components after removing one edge from the tree and also the edge which is removed. 

Note: If there are multiple edges that give the maximum value then print them all in any order.

Examples: 

Input: edges[][] = { {0, 5}, {0, 4}, {5, 1}, {5, 3}, {5, 2} }, val[ ] = { 7, 15, 9, 1, 1, 12}
Output: max_xor_product = 66
Edges: {0, 5}
Explanation: If we delete an edge {0, 5} then the tree will divide into two components.  
The XOR of the first component is (1^7) = 6. 
And the XOR of the second component is ( 12^15^1^9) = 11. 
The product of xor of those components is ( 6*11) = 66.
Similarly, if we delete an edge { 5, 1} tree again divide into two-component. 
The XOR of the first component is ( 15 ) ( because it has only one node) 
and XOR of the second component is ( 7^1^12^9^1) = 2. 
And the product of XOR of those components is ( 15 * 2 ) = 30.
If this is repeated the maximum value of the product of XOR of components will be 66,  
which can be achieved if we delete the edge {0, 5}.

See the image below to understand it better

Input: edges[][] = { {0, 1}, {0, 2}}, val[ ]={ 17, 17, 17}
Output: max_xor_product = 0
Edges: {{0, 1}, {0, 2}}

 

Naive Approach: Delete each edge and traverse through components and take xor of values of nodes in those components, then do the product of xor, store the maximum value and the edge corresponding to that value.

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

Efficient Method: This problem can be solved by precomputing XOR of subtree of each node and using bitwise XOR property as follows:

If an edge of a tree is deleted, then the tree will always divide into two components. The XOR of one component will be same as the XOR of the subtree (say X) and the other component will have XOR = (total XOR of all nodes ^ X).
For each edge, consider it to be removed and then find the XOR of both the components (using above observation) and their product. Keep track of the maximum and removing which edge results in that.

Follow the illustration shown below for a better understanding.

Illustration:

Consider the first example given below
edges[][] = { {0, 5}, {0, 4}, {5, 1}, {5, 3}, {5, 2} }, val[ ] = { 7, 15, 9, 1, 1, 12}

Remove edge {0, 4}:
        => Two components are {1} and {7, 12, 15, 1, 9}
        => XOR values are 1 and 12
        => Product = 1*12 = 12

Remove edge {0, 5}:
        => Two components are {1, 7} and {12, 15, 1, 9}
        => XOR values are 6 and 11
        => Product = 6*11 = 66

Remove edge {5, 1}:
        => Two components are {1, 7, 12, 1, 9} and {15}
        => XOR values are 2 and 15
        => Product = 2*15 = 30

Remove edge {5, 2}:
        => Two components are {1, 7, 12, 15, 1} and {9}
        => XOR values are 4 and 9
        => Product = 4*9 = 36

Remove edge {5, 3}:
        => Two components are {1, 7, 12, 15, 9} and {1}
        => XOR values are 1 and 12
        => Product = 1*12 = 12

So the maximum value is 66 which is achieved when the edge {0, 5} is removed

Follow the below steps to solve this problem: 

  • Calculate the XOR of all given values of all tree nodes (say tot_xor)
  • Create an array (say subtree_xor[])and store the bitwise xor of the subtree of ith node using DFS.
  • Now travel through the tree using DFS and for each node:
    • Consider the edge between current node and its parent is removed.
    • The two components will be: current node with its subtree and the remaining of the tree.
    • Calculate the bitwise xor of current node with its subtree and of the remaining tree as mentioned in the above observation.
    • Find the product of the XOR values.
    • Update maximum value and removed edges accordingly.
  • Return the maximum value and the removed edges.

Below is the implementation of the above approach: 

C++




// C++ code to implement the approach
 
#include <bits/stdc++.h>
using namespace std;
const int mxx = 1e6 + 7;
int subtree_xor[mxx];
 
unordered_map<long long,
              vector<pair<int, int> > >
    store;
 
// To add edges in tree
void addEdge(vector<int> tree[], int u, int v)
{
    tree[u].push_back(v);
    tree[v].push_back(u);
}
 
// To precompute xor value of each subtree
void dfs(vector<int> tree[], int val[],
         int cur_node, int par)
{
    // assign value of current node
    subtree_xor[cur_node] = val[cur_node];
 
    for (auto& child : tree[cur_node]) {
        if (child == par)
            continue;
        dfs(tree, val, child, cur_node);
        // take xor of all child node
        subtree_xor[cur_node]
            ^= subtree_xor[child];
    }
}
 
// To store all xor_product
// and it's corresponding edges
void store_xor_product(vector<int> tree[],
                       int cur_node,
                       int par, int tot_xor)
{
    for (auto& child : tree[cur_node]) {
        if (child == par)
            continue;
 
        // Xor of first component
        int first_comp_xor
            = subtree_xor[child];
 
        // Xor of second component
        int second_comp_xor
            = tot_xor ^ first_comp_xor;
 
        // Product can exceed int range
        // so store it in long long data type
        long long xor_product
            = first_comp_xor * 1LL
              * second_comp_xor;
 
        // Store edges corresponding
        // to its product
        store[xor_product].push_back({ cur_node,
                                       child });
 
        store_xor_product(tree, child,
                          cur_node, tot_xor);
    }
}
 
// To print edges corresponding
// to max_xor_product of components
void print_edges(long long mx_product)
{
    for (auto edges : store[mx_product]) {
        cout << edges.first << " "
             << edges.second << "\n";
    }
}
 
// Driver code
int findVal(int N, int val[],
            vector<vector<int> >& edges)
{
    int tot_xor = 0;
 
    // Store the xor of all values
    for (int i = 0; i < N; i++)
        tot_xor ^= val[i];
 
    vector<int> tree[N];
 
    // Create a tree from given edges
    for (int i = 0; i < N - 1; i++)
        addEdge(tree, edges[i][0],
                edges[i][1]);
 
    // Dfs travel to store subtree xor
    dfs(tree, val, 0, -1);
 
    // To store edges corresponding
    // to xor_product
    store_xor_product(tree, 0, -1, tot_xor);
 
    // Find maximum xor_product
    long long mx_product = -1;
    for (auto ele : store) {
        long long cur_product = ele.first;
        mx_product
            = max(mx_product, cur_product);
    }
    return mx_product;
}
 
// Driver code
int main()
{
    int N = 6;
    vector<vector<int> > edges = {
        { 0, 5 }, { 0, 4 }, { 5, 1 }, { 5, 3 }, { 5, 2 }
    };
 
    int val[] = { 7, 15, 9, 1, 1, 12 };
    int mx_product = findVal(N, val, edges);
    cout << mx_product << "\n";
 
    // To print edges corresponding
    // to maximum xor_product
    print_edges(mx_product);
    return 0;
}


Java




// Java code for the above approach:
import java.util.*;
 
public class Main {
  static int mxx = 1000007;
  static int subtree_xor[];
  static HashMap <Long,
  ArrayList <IntPair > > store;
  static class IntPair {
    int first;
    int second;
    IntPair(int x, int y) {
      this.first = x;
      this.second = y;
    }
  }
  // To add edges in tree
  static void addEdge(ArrayList <ArrayList <Integer>> tree, int u, int v)
  {
    tree.get(u).add(v);
    tree.get(v).add(u);
  }
 
  // To precompute xor value of each subtree
  static void dfs(ArrayList <ArrayList <Integer>> tree, int val[],
                  int cur_node, int par)
  {
    // assign value of current node
    subtree_xor[cur_node] = val[cur_node];
 
    for (Integer child : tree.get(cur_node)) {
      if (child == par)
        continue;
      dfs(tree, val, child, cur_node);
      // take xor of all child node
      subtree_xor[cur_node]
        ^= subtree_xor[child];
    }
  }
 
  // To store all xor_product
  // and it's corresponding edges
  static void store_xor_product(ArrayList <ArrayList <Integer>> tree,
                                int cur_node,
                                int par, int tot_xor)
  {
    for (Integer child : tree.get(cur_node)) {
      if (child == par)
        continue;
 
      // Xor of first component
      long first_comp_xor
        = subtree_xor[child];
 
      // Xor of second component
      long second_comp_xor
        = tot_xor ^ first_comp_xor;
 
      // Product can exceed int range
      // so store it in long long data type
      long xor_product
        = first_comp_xor * second_comp_xor;
 
      // Store edges corresponding
      // to its product
      if( ! store.containsKey(xor_product) ){
        store.put(xor_product,new ArrayList<IntPair> ());
      }
      store.get(xor_product).add(new IntPair(cur_node, child) );
 
      store_xor_product(tree, child,
                        cur_node, tot_xor);
    }
  }
 
  // To print edges corresponding
  // to max_xor_product of components
  static void print_edges(long mx_product)
  {
    if(store.containsKey(mx_product) ) {
      for (IntPair edges : store.get(mx_product) ) {
        System.out.println(edges.first + " "
                           + edges.second );
      }
    }
  }
 
  static long findVal(int N, int val[],
                      int[][] edges)
  {
    int tot_xor = 0;
 
    // Store the xor of all values
    for (int i = 0; i < N; i++)
      tot_xor ^= val[i];
    ArrayList <ArrayList <Integer> > tree =
      new ArrayList <ArrayList <Integer>> (N);
    for(int i = 0; i < N; i++){
      tree.add(new ArrayList <Integer>());
    }
 
    // Create a tree from given edges
    for (int i = 0; i < N - 1; i++)
      addEdge(tree, edges[i][0],
              edges[i][1]);
 
    // Dfs travel to store subtree xor
    dfs(tree, val, 0, -1);
 
    // To store edges corresponding
    // to xor_product
    store_xor_product(tree, 0, -1, tot_xor);
 
    // Find maximum xor_product
    long mx_product = -1;
    for (HashMap.Entry < Long, ArrayList <IntPair> > ele : store.entrySet()) {
      long cur_product = ele.getKey();
      mx_product
        = Math.max(mx_product, cur_product);
    }
    return mx_product;
  }
 
  // Driver Code
  public static void main(String args[]) {
    int N = 6;
    int[][] edges = {
      { 0, 5 }, { 0, 4 }, { 5, 1 }, { 5, 3 }, { 5, 2 }
    };
    subtree_xor = new int[mxx];
    store = new HashMap <Long, ArrayList <IntPair > > ();
    int val[] = { 7, 15, 9, 1, 1, 12 };
    long mx_product = findVal(N, val, edges);
    System.out.println( mx_product);
 
    // To print edges corresponding
    // to maximum xor_product
    print_edges(mx_product);
  }
}
 
// This code is contributed by Sachin Sahara (sachin801)


Python3




# Python code to implement the approach
mxx = 1000007
subtree_xor = [0] * mxx
store = {}
 
class IntPair:
    def __init__(self, x, y):
        self.first = x
        self.second = y
 
# To add edges in tree
def addEdge(tree, u, v):
    tree[u].append(v)
    tree[v].append(u)
 
# To precompute xor value of each subtree
def dfs(tree, val, cur_node, par):
    # assign value of current node
    subtree_xor[cur_node] = val[cur_node]
 
    for child in tree[cur_node]:
        if child == par:
            continue
        dfs(tree, val, child, cur_node)
        # take xor of all child node
        subtree_xor[cur_node] ^= subtree_xor[child]
 
# To store all xor_product
# and it's corresponding edges
def store_xor_product(tree, cur_node, par, tot_xor):
    for child in tree[cur_node]:
        if child == par:
            continue
 
        # Xor of first component
        first_comp_xor = subtree_xor[child]
 
        # Xor of second component
        second_comp_xor = tot_xor ^ first_comp_xor
 
        # Product can exceed int range
        # so store it in long long data type
        xor_product = first_comp_xor * second_comp_xor
 
        # Store edges corresponding to its product
        if xor_product not in store:
            store[xor_product] = []
        store[xor_product].append(IntPair(cur_node, child))
 
        store_xor_product(tree, child, cur_node, tot_xor)
 
# To print edges corresponding
# to max_xor_product of components
def print_edges(mx_product):
    if mx_product in store:
        for edges in store[mx_product]:
            print(edges.first, edges.second)
 
def findVal(N, val, edges):
    tot_xor = 0
 
    # Store the xor of all values
    for i in range(N):
        tot_xor ^= val[i]
    tree = [[] for i in range(N)]
 
    # Create a tree from given edges
    for i in range(N - 1):
        addEdge(tree, edges[i][0], edges[i][1])
 
    # Dfs travel to store subtree xor
    dfs(tree, val, 0, -1)
 
    # To store edges corresponding
    # to xor_product
    store_xor_product(tree, 0, -1, tot_xor)
 
    # Find maximum xor_product
    mx_product = -1
    for cur_product in store:
        mx_product = max(mx_product, cur_product)
    return mx_product
 
N = 6
edges = [
    [0, 5],
    [0, 4],
    [5, 1],
    [5, 3],
    [5, 2],
]
val = [7, 15, 9, 1, 1, 12]
mx_product = findVal(N, val, edges)
print(mx_product)
 
# To print edges corresponding
# to maximum xor_product
print_edges(mx_product)


C#




// C# code for the above approach:
using System;
using System.Collections.Generic;
 
public class GFG {
  static int mxx = 1000007;
  static int[] subtree_xor;
  static Dictionary<long, List<IntPair> > store;
  class IntPair {
    public int first;
    public int second;
    public IntPair(int x, int y)
    {
      this.first = x;
      this.second = y;
    }
  }
  // To add edges in tree
  static void addEdge(List<List<int> > tree, int u, int v)
  {
    tree[u].Add(v);
    tree[v].Add(u);
  }
 
  // To precompute xor value of each subtree
  static void dfs(List<List<int> > tree, int[] val,
                  int cur_node, int par)
  {
    // assign value of current node
    subtree_xor[cur_node] = val[cur_node];
 
    foreach(int child in tree[cur_node])
    {
      if (child == par)
        continue;
      dfs(tree, val, child, cur_node);
      // take xor of all child node
      subtree_xor[cur_node] ^= subtree_xor[child];
    }
  }
 
  // To store all xor_product
  // and it's corresponding edges
  static void store_xor_product(List<List<int> > tree,
                                int cur_node, int par,
                                int tot_xor)
  {
    foreach(int child in tree[cur_node])
    {
      if (child == par)
        continue;
 
      // Xor of first component
      long first_comp_xor = subtree_xor[child];
 
      // Xor of second component
      long second_comp_xor = tot_xor ^ first_comp_xor;
 
      // Product can exceed int range
      // so store it in long long data type
      long xor_product
        = first_comp_xor * second_comp_xor;
 
      // Store edges corresponding
      // to its product
      if (!store.ContainsKey(xor_product)) {
        store.Add(xor_product, new List<IntPair>());
      }
      store[xor_product].Add(
        new IntPair(cur_node, child));
 
      store_xor_product(tree, child, cur_node,
                        tot_xor);
    }
  }
 
  // To print edges corresponding
  // to max_xor_product of components
  static void print_edges(long mx_product)
  {
    if (store.ContainsKey(mx_product)) {
      foreach(IntPair edges in store[mx_product])
      {
        Console.WriteLine(edges.first + " "
                          + edges.second);
      }
    }
  }
 
  static long findVal(int N, int[] val, int[][] edges)
  {
    int tot_xor = 0;
 
    // Store the xor of all values
    for (int i = 0; i < N; i++)
      tot_xor ^= val[i];
    List<List<int> > tree = new List<List<int> >(N);
    for (int i = 0; i < N; i++) {
      tree.Add(new List<int>());
    }
 
    // Create a tree from given edges
    for (int i = 0; i < N - 1; i++)
      addEdge(tree, edges[i][0], edges[i][1]);
 
    // Dfs travel to store subtree xor
    dfs(tree, val, 0, -1);
 
    // To store edges corresponding
    // to xor_product
    store_xor_product(tree, 0, -1, tot_xor);
 
    // Find maximum xor_product
    long mx_product = -1;
    foreach(
      KeyValuePair<long, List<IntPair> > ele in store)
    {
      long cur_product = ele.Key;
      mx_product = Math.Max(mx_product, cur_product);
    }
    return mx_product;
  }
 
  // Driver Code
  static public void Main()
  {
    int N = 6;
    int[][] edges
      = { new int[] { 0, 5 }, new int[] { 0, 4 },
         new int[] { 5, 1 }, new int[] { 5, 3 },
         new int[] { 5, 2 } };
    subtree_xor = new int[mxx];
    store = new Dictionary<long, List<IntPair> >();
    int[] val = { 7, 15, 9, 1, 1, 12 };
    long mx_product = findVal(N, val, edges);
    Console.WriteLine(mx_product);
 
    // To print edges corresponding
    // to maximum xor_product
    print_edges(mx_product);
  }
}
 
// This code is contributed by akashish__


Javascript




       // JavaScript code for the above approach
       const mxx = 1000007;
       let subtree_xor = new Array(mxx);
       let store = new Map();
 
       class IntPair {
           constructor(x, y) {
               this.first = x;
               this.second = y;
           }
       }
 
       // To add edges in tree
       function addEdge(tree, u, v) {
           tree[u].push(v);
           tree[v].push(u);
       }
 
       // To precompute xor value of each subtree
       function dfs(tree, val, cur_node, par) {
           // assign value of current node
           subtree_xor[cur_node] = val[cur_node];
 
           for (const child of tree[cur_node]) {
               if (child === par) continue;
               dfs(tree, val, child, cur_node);
               // take xor of all child node
               subtree_xor[cur_node] ^= subtree_xor[child];
           }
       }
 
       // To store all xor_product
       // and it's corresponding edges
       function store_xor_product(tree, cur_node, par, tot_xor) {
           for (const child of tree[cur_node]) {
               if (child === par) continue;
 
               // Xor of first component
               const first_comp_xor = subtree_xor[child];
 
               // Xor of second component
               const second_comp_xor = tot_xor ^ first_comp_xor;
 
               // Product can exceed int range
               // so store it in long long data type
               const xor_product = first_comp_xor * second_comp_xor;
 
               // Store edges corresponding to its product
               if (!store.has(xor_product)) {
                   store.set(xor_product, []);
               }
               store.get(xor_product).push(new IntPair(cur_node, child));
 
               store_xor_product(tree, child, cur_node, tot_xor);
           }
       }
 
       // To print edges corresponding
       // to max_xor_product of components
       function print_edges(mx_product) {
           if (store.has(mx_product)) {
               for (const edges of store.get(mx_product)) {
                   console.log(edges.first + " " + edges.second);
               }
           }
       }
 
       function findVal(N, val, edges) {
           let tot_xor = 0;
 
           // Store the xor of all values
           for (let i = 0; i < N; i++) tot_xor ^= val[i];
           const tree = new Array(N);
           for (let i = 0; i < N; i++) {
               tree[i] = [];
           }
 
           // Create a tree from given edges
           for (let i = 0; i < N - 1; i++) {
               addEdge(tree, edges[i][0], edges[i][1]);
           }
 
           // Dfs travel to store subtree xor
           dfs(tree, val, 0, -1);
 
           // To store edges corresponding
           // to xor_product
           store_xor_product(tree, 0, -1, tot_xor);
 
           // Find maximum xor_product
           let mx_product = -1;
           for (const ele of store.entries()) {
               const cur_product = ele[0];
               mx_product = Math.max(mx_product, cur_product);
           }
           return mx_product;
       }
 
 
       const N = 6;
       const edges = [
           [0, 5],
           [0, 4],
           [5, 1],
           [5, 3],
           [5, 2],
       ];
 
       const val = [7, 15, 9, 1, 1, 12];
       const mx_product = findVal(N, val, edges);
       console.log(mx_product);
 
       // To print edges corresponding
       // to maximum xor_product
       print_edges(mx_product);
 
// This code is contributed by Potta Lokesh


Output

66
0 5

Time Complexity: O( N )
Auxiliary Space: O( N ) 



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