XOR of a submatrix queries

Given an N * N matrix and q queries, each containing position of top-left and bottom-right corner of a rectangular sub-matrix, the task is to find the xor of all the elements from this sub-matrix.
Examples:
Input: arr[][] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, q[] = {{1, 1, 2, 2}, {1, 2, 2, 2}}
Output:
2
15
Query 1: 5 ^ 6 ^ 8 ^ 9 = 2
Query 2: 6 ^ 9 = 15
Input: arr[][] = {{21, 2}, { 14, 5}}, q[] = {{0, 1, 1, 1}, {0, 0, 1, 1}}
Output:
7
28
A simple solution is to find the XOR of the entire sub-matrix for each query. Thus, the worst case time complexity for each query will be O(n2).
Efficient Approach: We are all familiar with the idea of prefix XOR on linear array i.e.
if arr[] = {1, 2, 3, 4} and we calculate prefixXOR[] = {1, 3, 0, 4} where prefixXOR[i] stores the XOR of values from arr[0] to arr[i]
Then the XOR of sub-array arr[i] to arr[j] can be found as prefixXOR[j] ^ prefixXOR[i – 1]
For example, the XOR of sub-array {2, 3} will be XOR(0, 1) = 1
This is because in the prefixXOR values for {1, 2, 3} and {1}, the value 1 got repeated twice which will give 0 as the XOR result and will not affect the value of the other XOR operations.
We will try to extend the same to the 2-D matrix. We will compute a prefix-XOR matrix which will help us in solving each query in O(1).
In this case, our prefix-XOR matrix at position (R, C) will store the XOR of the rectangular sub-matrix with top-left corner at(0, 0) and bottom-right corner at (R, C).
We calculate the prefix-XOR in two steps.
- Calculate the prefix-XOR for each row of the original matrix from left to right.
- On the above matrix, calculate the prefix XOR for each column from top to bottom.
Once, we have the required prefix XOR-matrix, we can answer the queries with simplicity. XOR of a sub-matrix from (R1, C1) to (R2, C2) can be computed as prefix_xor[R2][C2] ^ prefix_xor[R1 – 1][C2] ^ prefix_xor[R2][C1 – 1] ^ prefix_xor[R1 – 1][C1 – 1].
Note: If R1 or C1 equals 0, then R1 – 1 or C1 – 1 should also be 0.
Below is the implementation of the above approach:
C++
// C++ implementation of the approach#include <iostream>#define n 3using namespace std;// Function to pre-compute the xorvoid preComputeXor(int arr[][n], int prefix_xor[][n]){ // Left to right prefix xor // for each row for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) { if (j == 0) prefix_xor[i][j] = arr[i][j]; else prefix_xor[i][j] = (prefix_xor[i][j - 1] ^ arr[i][j]); } // Top to bottom prefix xor // for each column for (int i = 0; i < n; i++) for (int j = 1; j < n; j++) prefix_xor[j][i] = (prefix_xor[j - 1][i] ^ prefix_xor[j][i]);}// Function to process the queries// x1, x2, y1, y2 represent the// positions of the top-left// and bottom right cornersint ansQuerie(int prefix_xor[][n], int x1, int y1, int x2, int y2){ // To store the xor values int xor_1 = 0, xor_2 = 0, xor_3 = 0; // Finding the values we need to xor // with value at (x2, y2) in prefix-xor // matrix if (x1 != 0) xor_1 = prefix_xor[x1 - 1][y2]; if (y1 != 0) xor_2 = prefix_xor[x2][y1 - 1]; if (x1 != 0 and y1 != 0) xor_3 = prefix_xor[x1 - 1][y1 - 1]; // Return the required prefix xor return ((prefix_xor[x2][y2] ^ xor_1) ^ (xor_2 ^ xor_3));}// Driver codeint main(){ int arr[][n] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; // To store pre-computed xor int prefix_xor[n][n]; // Pre-computing xor preComputeXor(arr, prefix_xor); // Queries cout << ansQuerie(prefix_xor, 1, 1, 2, 2) << endl; cout << ansQuerie(prefix_xor, 1, 2, 2, 2) << endl; return 0;} |
Java
// Java implementation of the approach class GfG{ static int n = 3;// Function to pre-compute the xor static void preComputeXor(int arr[][], int prefix_xor[][]) { // Left to right prefix xor // for each row for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) { if (j == 0) prefix_xor[i][j] = arr[i][j]; else prefix_xor[i][j] = (prefix_xor[i][j - 1] ^ arr[i][j]); } // Top to bottom prefix xor // for each column for (int i = 0; i < n; i++) for (int j = 1; j < n; j++) prefix_xor[j][i] = (prefix_xor[j - 1][i] ^ prefix_xor[j][i]); } // Function to process the queries // x1, x2, y1, y2 represent the // positions of the top-left // and bottom right corners static int ansQuerie(int prefix_xor[][], int x1, int y1, int x2, int y2) { // To store the xor values int xor_1 = 0, xor_2 = 0, xor_3 = 0; // Finding the values we need to xor // with value at (x2, y2) in prefix-xor // matrix if (x1 != 0) xor_1 = prefix_xor[x1 - 1][y2]; if (y1 != 0) xor_2 = prefix_xor[x2][y1 - 1]; if (x1 != 0 && y1 != 0) xor_3 = prefix_xor[x1 - 1][y1 - 1]; // Return the required prefix xor return ((prefix_xor[x2][y2] ^ xor_1) ^ (xor_2 ^ xor_3)); } // Driver code public static void main(String[] args) { int arr[][] = new int[][]{{ 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }}; // To store pre-computed xor int prefix_xor[][] = new int[n][n]; // Pre-computing xor preComputeXor(arr, prefix_xor); // Queries System.out.println(ansQuerie(prefix_xor, 1, 1, 2, 2)); System.out.println(ansQuerie(prefix_xor, 1, 2, 2, 2)); } } // This code is contributed by // Prerna Saini. |
Python3
n = 3# Function to pre-compute the xordef preComputeXor(arr, prefix_xor): # Left to right prefix xor # for each row for i in range(n): for j in range(n): if (j == 0): prefix_xor[i][j] = arr[i][j] else: prefix_xor[i][j] = (prefix_xor[i][j - 1] ^ arr[i][j]) # Top to bottom prefix xor # for each column for i in range(n): for j in range(1, n): prefix_xor[j][i] = (prefix_xor[j - 1][i] ^ prefix_xor[j][i])# Function to process the queries# x1, x2, y1, y2 represent the# positions of the top-left# and bottom right cornersdef ansQuerie(prefix_xor, x1, y1, x2, y2): # To store the xor values xor_1, xor_2, xor_3 = 0, 0, 0 # Finding the values we need to xor # with value at (x2, y2) in prefix-xor # matrix if (x1 != 0): xor_1 = prefix_xor[x1 - 1][y2] if (y1 != 0): xor_2 = prefix_xor[x2][y1 - 1] if (x1 != 0 and y1 != 0): xor_3 = prefix_xor[x1 - 1][y1 - 1] # Return the required prefix xor return ((prefix_xor[x2][y2] ^ xor_1) ^ (xor_2 ^ xor_3))# Driver codearr = [[ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ]]# To store pre-computed xorprefix_xor = [[0 for i in range(n)] for i in range(n)]# Pre-computing xorpreComputeXor(arr, prefix_xor)# Queriesprint(ansQuerie(prefix_xor, 1, 1, 2, 2))print(ansQuerie(prefix_xor, 1, 2, 2, 2))# This code is contributed by Mohit Kumar |
C#
// C# implementation of the approach using System;class GfG { static int n = 3; // Function to pre-compute the xor static void preComputeXor(int [,]arr, int [,]prefix_xor) { // Left to right prefix xor // for each row for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) { if (j == 0) prefix_xor[i, j] = arr[i, j]; else prefix_xor[i, j] = (prefix_xor[i, j - 1] ^ arr[i, j]); } // Top to bottom prefix xor // for each column for (int i = 0; i < n; i++) for (int j = 1; j < n; j++) prefix_xor[j, i] = (prefix_xor[j - 1, i] ^ prefix_xor[j, i]); } // Function to process the queries // x1, x2, y1, y2 represent the // positions of the top-left // and bottom right corners static int ansQuerie(int [,]prefix_xor, int x1, int y1, int x2, int y2) { // To store the xor values int xor_1 = 0, xor_2 = 0, xor_3 = 0; // Finding the values we need to xor // with value at (x2, y2) in prefix-xor // matrix if (x1 != 0) xor_1 = prefix_xor[x1 - 1, y2]; if (y1 != 0) xor_2 = prefix_xor[x2, y1 - 1]; if (x1 != 0 && y1 != 0) xor_3 = prefix_xor[x1 - 1, y1 - 1]; // Return the required prefix xor return ((prefix_xor[x2,y2] ^ xor_1) ^ (xor_2 ^ xor_3)); } // Driver code public static void Main() { int [,]arr = {{ 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }}; // To store pre-computed xor int [,]prefix_xor = new int[n, n]; // Pre-computing xor preComputeXor(arr, prefix_xor); // Queries Console.WriteLine(ansQuerie(prefix_xor, 1, 1, 2, 2)); Console.WriteLine(ansQuerie(prefix_xor, 1, 2, 2, 2)); } } // This code is contributed by Ryuga |
PHP
<?php// PHP implementation of the approach$n = 3;// Function to pre-compute the xorfunction preComputeXor($arr, &$prefix_xor){ global $n; // Left to right prefix xor // for each row for ($i = 0; $i < $n; $i++) for ($j = 0; $j < $n; $j++) { if ($j == 0) $prefix_xor[$i][$j] = $arr[$i][$j]; else $prefix_xor[$i][$j] = ($prefix_xor[$i][$j - 1] ^ $arr[$i][$j]); } // Top to bottom prefix xor // for each column for ($i = 0; $i < $n; $i++) for ($j = 1; $j < $n; $j++) $prefix_xor[$j][$i] = ($prefix_xor[$j - 1][$i] ^ $prefix_xor[$j][$i]);}// Function to process the queries// x1, x2, y1, y2 represent the// positions of the top-left// and bottom right cornersfunction ansQuerie($prefix_xor, $x1, $y1, $x2, $y2){ // To store the xor values $xor_1 = $xor_2 = $xor_3 = 0; // Finding the values we need to xor // with value at (x2, y2) in prefix-xor // matrix if ($x1 != 0) $xor_1 = $prefix_xor[$x1 - 1][$y2]; if ($y1 != 0) $xor_2 = $prefix_xor[$x2][$y1 - 1]; if ($x1 != 0 and $y1 != 0) $xor_3 = $prefix_xor[$x1 - 1][$y1 - 1]; // Return the required prefix xor return (($prefix_xor[$x2][$y2] ^ $xor_1) ^ ($xor_2 ^ $xor_3));}// Driver code$arr = array(array( 1, 2, 3 ), array( 4, 5, 6 ), array( 7, 8, 9 ));// To store pre-computed xor$prefix_xor = array_fill(0, $n, array_fill(0, $n, 0));// Pre-computing xorpreComputeXor($arr, $prefix_xor);// Queriesecho ansQuerie($prefix_xor, 1, 1, 2, 2) . "\n";echo ansQuerie($prefix_xor, 1, 2, 2, 2);// This code is contributed by mits?> |
Javascript
<script>// Javascript implementation of the approach var n = 3; // Function to pre-compute the xor function preComputeXor(arr , prefix_xor) { // Left to right prefix xor // for each row for (i = 0; i < n; i++) for (j = 0; j < n; j++) { if (j == 0) prefix_xor[i][j] = arr[i][j]; else prefix_xor[i][j] = (prefix_xor[i][j - 1] ^ arr[i][j]); } // Top to bottom prefix xor // for each column for (i = 0; i < n; i++) for (j = 1; j < n; j++) prefix_xor[j][i] = (prefix_xor[j - 1][i] ^ prefix_xor[j][i]); } // Function to process the queries // x1, x2, y1, y2 represent the // positions of the top-left // and bottom right corners function ansQuerie(prefix_xor , x1 , y1 , x2 , y2) { // To store the xor values var xor_1 = 0, xor_2 = 0, xor_3 = 0; // Finding the values we need to xor // with value at (x2, y2) in prefix-xor // matrix if (x1 != 0) xor_1 = prefix_xor[x1 - 1][y2]; if (y1 != 0) xor_2 = prefix_xor[x2][y1 - 1]; if (x1 != 0 && y1 != 0) xor_3 = prefix_xor[x1 - 1][y1 - 1]; // Return the required prefix xor return ((prefix_xor[x2][y2] ^ xor_1) ^ (xor_2 ^ xor_3)); } // Driver code var arr = [[ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ]; // To store pre-computed xor var prefix_xor = Array(n); for(var i = 0;i<n;i++) prefix_xor[i] = Array(n).fill(0); // Pre-computing xor preComputeXor(arr, prefix_xor); // Queries document.write(ansQuerie(prefix_xor, 1, 1, 2, 2)+ "<br/>"); document.write(ansQuerie(prefix_xor, 1, 2, 2, 2));// This code contributed by umadevi9616</script> |
2 15
Time Complexity: O(n2)
Auxiliary Space: O(n2), since n2 extra space has been taken.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 zambiatek!



