Skip to content
Related Articles

Related Articles

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

View Discussion
Improve Article
Save Article
  • Last Updated : 06 Jun, 2022
View Discussion
Improve Article
Save Article

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)


Output

66
0 5

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


My Personal Notes arrow_drop_up
Recommended Articles
Page :

Start Your Coding Journey Now!