Prefix XOR precomputes the XOR from the start to each index, enabling O(1) subarray XOR queries.
Its core idea:
XOR of subarray
[l, r]=prefix[r] ^ prefix[l-1]— because XOR cancels itself (x ^ x = 0).
Focus on recognizing:
“XOR of subarray” + “Range query” = Prefix XOR
Core Template
Watch the prefix XOR of [3,5,2,7] build to [3,6,4,3], then xor(1..2) resolve as 4 ^ 3 = 7. Press ▶ to animate.
⚠️ Animation & Content Notice
The animation work is not fully finished — some animations may have slight errors.
If there is a major error in the content or if the animation or content is difficult to understand, please contact us at rayyancodingschool@gmail.com.
Prefix XOR (Build + O(1) Range Queries)
Precompute a prefix-XOR array X where X[i] is the XOR of the first i+1 elements, then answer any range XOR in O(1) via X[r] ^ X[l-1]. XOR's x ^ x = 0 property is what makes subtraction possible.
arr = [3,5,2,7]. Seed X[0]=3, then X[i] = X[i-1] ^ nums[i]. Watch the bit flips: 3^5 = 6 (011^101=110), 6^2 = 4, 4^7 = 3. Result X = [3,6,4,3]; the last cell is the XOR of everything. ('·' cells are not-yet-computed prefix entries.)
1
X[0] = nums[0]
2
for i in 1..n-1:
3
X[i] = X[i-1] ^ nums[i]
1
# X prebuilt:
2
xor(l..r) = X[r] ^ X[l-1]
3
4
query(1..2) → X[2] ^ X[0]
5
query(0..3) → X[3]
public int xorQuery(int[] nums, int l, int r) {
int n = nums.length;
int[] prefix = new int[n];
prefix[0] = nums[0];
for (int i = 1; i < n; i++) {
prefix[i] = prefix[i - 1] ^ nums[i];
}
if (l == 0) return prefix[r];
return prefix[r] ^ prefix[l - 1];
}def xor_query(nums, l, r):
n = len(nums)
prefix = [0] * n
prefix[0] = nums[0]
for i in range(1, n):
prefix[i] = prefix[i - 1] ^ nums[i]
if l == 0:
return prefix[r]
return prefix[r] ^ prefix[l - 1]int xorQuery(vector<int>& nums, int l, int r) {
int n = nums.size();
vector<int> prefix(n);
prefix[0] = nums[0];
for (int i = 1; i < n; i++) {
prefix[i] = prefix[i - 1] ^ nums[i];
}
if (l == 0) return prefix[r];
return prefix[r] ^ prefix[l - 1];
}function xorQuery(nums, l, r) {
const n = nums.length;
const prefix = Array(n);
prefix[0] = nums[0];
for (let i = 1; i < n; i++) {
prefix[i] = prefix[i - 1] ^ nums[i];
}
if (l === 0) return prefix[r];
return prefix[r] ^ prefix[l - 1];
}Identical skeleton to prefix sum — only
+becomes^. That works because XOR is its own inverse.
Why It Works
Every element before l appears in both prefix[r] and prefix[l-1]:
prefix[r] = a0 ^ a1 ^ ... ^ al-1 ^ al ^ ... ^ ar
prefix[l-1] = a0 ^ a1 ^ ... ^ al-1
prefix[r] ^ prefix[l-1] = al ^ ... ^ ar (duplicates cancel)
Any operation that is its own inverse can replace subtraction here — XOR is the classic one.
Common Mistakes
Using subtraction instead of XOR.
prefix[r] − prefix[l−1] computes nothing meaningful for XOR ranges.
Forgetting the l == 0 guard.
prefix[-1] crashes or wraps — handle queries starting at index 0 explicitly (or pad with a leading 0).
Complexity
| Operation | Time |
|---|---|
| Build | O(n) |
| Query | O(1) |
Premium Content
Unlock Prefix XOR and all premium lessons with a subscription.
From ₹199.99/year — See plans