Related Articles

# Range Update Queries to XOR with 1 in a Binary Array.

• Last Updated : 07 Jan, 2021

Given a binary array arr[] of size N. The task is to answer Q queries which can be of any one type from below:
Type 1 – 1 l r : Performs bitwise xor operation on all the array elements from l to r with 1.
Type 2 – 2 l r : Returns the minimum distance between two elements with value 1 in a subarray [l, r].
Type 3 – 3 l r : Returns the maximum distance between two elements with value 1 in a subarray [l, r].
Type 4 – 4 l r : Returns the minimum distance between two elements with value 0 in a subarray [l, r].
Type 5 – 5 l r : Returns the maximum distance between two elements with value 0 in a subarray [l, r].
Examples:

Input : arr[] = {1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0}, q=5
Output : 2 2 3 2
Explanation :
query 1 : Type 2, l=3, r=7
Range 3 to 7 contains { 1, 0, 1, 0, 1 }.
So, the minimum distance between two elements with value 1 is 2.
query 2 : Type 3, l=2, r=5
Range 2 to 5 contains { 0, 1, 0, 1 }.
So, the maximum distance between two elements with value 1 is 2.
query 3 : Type 1, l=1, r=4
After update array becomes {1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0}
query 4 : Type 4, l=3, r=7
Range 3 to 7 in updated array contains { 0, 1, 1, 0, 1 }.
So, the minimum distance between two elements with value 0 is 3.
query 5 : Type 5, l=4, r=9
Range 4 to 9 contains { 1, 1, 0, 1, 0, 1 }.
So, the maximum distance between two elements with value 0 is 2.

Approach:
We will create a segment tree and use range updates with lazy propagation to solve this.

1. Each node in the segment tree will have the index of leftmost 1 as well as rightmost 1, leftmost 0 as well as rightmost 0 and integers containing the maximum and minimum distance between any elements with value 1 in a subarray {l, r} as well as the maximum and minimum distance between any elements with value 0 in a subarray {l, r}.

2. Now, in this segment tree we can merge left and right nodes as below:

## CPP

 `// l1 = leftmost index of 1, l0 = leftmost index of 0.``// r1 = rightmost index of 1, r0 = rightmost index of 0.``// max1 = maximum distance between two 1’s.``// max0 = maximum distance between two 0’s.``// min1 = minimum distance between two 1’s.``// min0 = minimum distance between two 0’s.``node Merge(node left, node right)``{``    ``node cur;``    ` `    ``if` `left.l0 is valid``        ``cur.l0 = left.l0``    ``else``        ``cur.l0 = r.l0``    ``// We will do this for all values``    ``// i.e. cur.r0, cur.l1, cur.r1, cur.l0``    ` `    ``// To find the min and max difference between two 1's and 0's``    ``// we will take min/max value of left side, right side and``    ``// difference between rightmost index of 1/0 in right node``    ``// and leftmost index of 1/0 in left node respectively.``        ` `     ``cur.min0 = minimum of left.min0 and right.min0`` ` `     ``if` `left.r0 is valid and right.l0 is valid``        ``cur.min0 = minimum of cur.min0 and (right.l0 - left.r0)``    ``// We will do this for all max/min values``    ``// i.e. cur.min0, cur.min1, cur.max1, cur.max0``        ` `    ``return` `cur;``}`
1.
2. To handle the range update query, we will use lazy propagation. The update query asks us to xor all the elements in the range from l to r with 1, and from observations, we know that :

```       0 xor 1 = 1
1 xor 1 = 0```
1. Hence, we can observe that after this update all the 0’s will change to 1 and all the 1’s will change to 0. Thus, in our segment tree nodes, all the corresponding values for 0 and 1 will also get swapped i.e.

```       l0 and l1 will get swapped
r0 and r1 will get swapped
min0 and min1 will get swapped
max0 and max1 will get swapped```
1.
2. Then, finally to find the answer to tasks 2, 3, 4 and 5 we just need to call query function for the given range {l, r} and i order to find the answer to task 1 we need to call the range update function.

Below is the implementation of the above approach:

## CPP

 `// C++ program for the given problem``#include ``using` `namespace` `std;` `int` `lazy;` `// Class for each node``// in the segment tree``class` `node {``public``:``    ``int` `l1, r1, l0, r0;``    ``int` `min0, max0, min1, max1;` `    ``node()``    ``{``        ``l1 = r1 = l0 = r0 = -1;` `        ``max1 = max0 = INT_MIN;``        ``min1 = min0 = INT_MAX;``    ``}` `} seg;` `// A utility function for``// merging two nodes``node MergeUtil(node l, node r)``{``    ``node x;` `    ``x.l0 = (l.l0 != -1) ? l.l0 : r.l0;``    ``x.r0 = (r.r0 != -1) ? r.r0 : l.r0;` `    ``x.l1 = (l.l1 != -1) ? l.l1 : r.l1;``    ``x.r1 = (r.r1 != -1) ? r.r1 : l.r1;` `    ``x.min0 = min(l.min0, r.min0);``    ``if` `(l.r0 != -1 && r.l0 != -1)``        ``x.min0 = min(x.min0, r.l0 - l.r0);` `    ``x.min1 = min(l.min1, r.min1);``    ``if` `(l.r1 != -1 && r.l1 != -1)``        ``x.min1 = min(x.min1, r.l1 - l.r1);` `    ``x.max0 = max(l.max0, r.max0);``    ``if` `(l.l0 != -1 && r.r0 != -1)``        ``x.max0 = max(x.max0, r.r0 - l.l0);` `    ``x.max1 = max(l.max1, r.max1);``    ``if` `(l.l1 != -1 && r.r1 != -1)``        ``x.max1 = max(x.max1, r.r1 - l.l1);` `    ``return` `x;``}` `// utility function``// for updating a node``node UpdateUtil(node x)``{``    ``swap(x.l0, x.l1);``    ``swap(x.r0, x.r1);``    ``swap(x.min1, x.min0);``    ``swap(x.max0, x.max1);` `    ``return` `x;``}` `// A recursive function that constructs``// Segment Tree for given string``void` `Build(``int` `qs, ``int` `qe, ``int` `ind, ``int` `arr[])``{``    ``// If start is equal to end then``    ``// insert the array element``    ``if` `(qs == qe) {``        ``if` `(arr[qs] == 1) {``            ``seg[ind].l1 = seg[ind].r1 = qs;``        ``}``        ``else` `{``            ``seg[ind].l0 = seg[ind].r0 = qs;``        ``}` `        ``lazy[ind] = 0;``        ``return``;``    ``}``    ``int` `mid = (qs + qe) >> 1;` `    ``// Build the segment tree``    ``// for range qs to mid``    ``Build(qs, mid, ind << 1, arr);` `    ``// Build the segment tree``    ``// for range mid+1 to qe``    ``Build(mid + 1, qe, ind << 1 | 1, arr);` `    ``// merge the two child nodes``    ``// to obtain the parent node``    ``seg[ind] = MergeUtil(``        ``seg[ind << 1],``        ``seg[ind << 1 | 1]);``}` `// Query in a range qs to qe``node Query(``int` `qs, ``int` `qe,``           ``int` `ns, ``int` `ne, ``int` `ind)``{``    ``if` `(lazy[ind] != 0) {``        ``seg[ind] = UpdateUtil(seg[ind]);``        ``if` `(ns != ne) {``            ``lazy[ind * 2] ^= lazy[ind];``            ``lazy[ind * 2 + 1] ^= lazy[ind];``        ``}``        ``lazy[ind] = 0;``    ``}` `    ``node x;` `    ``// If the range lies in this segment``    ``if` `(qs <= ns && qe >= ne)``        ``return` `seg[ind];` `    ``// If the range is out of the bounds``    ``// of this segment``    ``if` `(ne < qs || ns > qe || ns > ne)``        ``return` `x;` `    ``// Else query for the right and left``    ``// child node of this subtree``    ``// and merge them``    ``int` `mid = (ns + ne) >> 1;` `    ``node l = Query(qs, qe, ns,``                   ``mid, ind << 1);``    ``node r = Query(qs, qe,``                   ``mid + 1, ne,``                   ``ind << 1 | 1);` `    ``x = MergeUtil(l, r);``    ``return` `x;``}` `// range update using lazy prpagation``void` `RangeUpdate(``int` `us, ``int` `ue,``                 ``int` `ns, ``int` `ne, ``int` `ind)``{``    ``if` `(lazy[ind] != 0) {``        ``seg[ind] = UpdateUtil(seg[ind]);``        ``if` `(ns != ne) {``            ``lazy[ind * 2] ^= lazy[ind];``            ``lazy[ind * 2 + 1] ^= lazy[ind];``        ``}``        ``lazy[ind] = 0;``    ``}` `    ``// If the range is out of the bounds``    ``// of this segment``    ``if` `(ns > ne || ns > ue || ne < us)``        ``return``;` `    ``// If the range lies in this segment``    ``if` `(ns >= us && ne <= ue) {``        ``seg[ind] = UpdateUtil(seg[ind]);``        ``if` `(ns != ne) {``            ``lazy[ind * 2] ^= 1;``            ``lazy[ind * 2 + 1] ^= 1;``        ``}``        ``return``;``    ``}` `    ``// Else query for the right and left``    ``// child node of this subtree``    ``// and merge them``    ``int` `mid = (ns + ne) >> 1;``    ``RangeUpdate(us, ue, ns, mid, ind << 1);``    ``RangeUpdate(us, ue, mid + 1, ne, ind << 1 | 1);` `    ``node l = seg[ind << 1], r = seg[ind << 1 | 1];``    ``seg[ind] = MergeUtil(l, r);``}` `// Driver code``int` `main()``{` `    ``int` `arr[] = { 1, 1, 0,``                  ``1, 0, 1,``                  ``0, 1, 0,``                  ``1, 0, 1,``                  ``1, 0 };``    ``int` `n = ``sizeof``(arr) / ``sizeof``(arr);` `    ``// Build the segment tree``    ``Build(0, n - 1, 1, arr);` `    ``// Query of Type 2 in the range 3 to 7``    ``node ans = Query(3, 7, 0, n - 1, 1);``    ``cout << ans.min1 << ``"\n"``;` `    ``// Query of Type 3 in the range 2 to 5``    ``ans = Query(2, 5, 0, n - 1, 1);``    ``cout << ans.max1 << ``"\n"``;` `    ``// Query of Type 1 in the range 1 to 4``    ``RangeUpdate(1, 4, 0, n - 1, 1);` `    ``// Query of Type 4 in the range 3 to 7``    ``ans = Query(3, 7, 0, n - 1, 1);``    ``cout << ans.min0 << ``"\n"``;` `    ``// Query of Type 5 in the range 4 to 9``    ``ans = Query(4, 9, 0, n - 1, 1);``    ``cout << ans.max0 << ``"\n"``;` `    ``return` `0;``}`

## Python3

 `# Python program for the given problem``from` `sys ``import` `maxsize``from` `typing ``import` `List``INT_MAX ``=` `maxsize``INT_MIN ``=` `-``maxsize``lazy ``=` `[``0` `for` `_ ``in` `range``(``100001``)]` `# Class for each node``# in the segment tree``class` `node:``    ``def` `__init__(``self``) ``-``> ``None``:``        ``self``.l1 ``=` `self``.r1 ``=` `self``.l0 ``=` `self``.r0 ``=` `-``1``        ``self``.max0 ``=` `self``.max1 ``=` `INT_MIN``        ``self``.min0 ``=` `self``.min1 ``=` `INT_MAX` `seg ``=` `[node() ``for` `_ ``in` `range``(``100001``)]` `# A utility function for``# merging two nodes``def` `MergeUtil(l: node, r: node) ``-``> node:``    ``x ``=` `node()` `    ``x.l0 ``=` `l.l0 ``if` `(l.l0 !``=` `-``1``) ``else` `r.l0``    ``x.r0 ``=` `r.r0 ``if` `(r.r0 !``=` `-``1``) ``else` `l.r0` `    ``x.l1 ``=` `l.l1 ``if` `(l.l1 !``=` `-``1``) ``else` `r.l1``    ``x.r1 ``=` `r.r1 ``if` `(r.r1 !``=` `-``1``) ``else` `l.r1` `    ``x.min0 ``=` `min``(l.min0, r.min0)``    ``if` `(l.r0 !``=` `-``1` `and` `r.l0 !``=` `-``1``):``        ``x.min0 ``=` `min``(x.min0, r.l0 ``-` `l.r0)` `    ``x.min1 ``=` `min``(l.min1, r.min1)``    ``if` `(l.r1 !``=` `-``1` `and` `r.l1 !``=` `-``1``):``        ``x.min1 ``=` `min``(x.min1, r.l1 ``-` `l.r1)` `    ``x.max0 ``=` `max``(l.max0, r.max0)``    ``if` `(l.l0 !``=` `-``1` `and` `r.r0 !``=` `-``1``):``        ``x.max0 ``=` `max``(x.max0, r.r0 ``-` `l.l0)` `    ``x.max1 ``=` `max``(l.max1, r.max1)``    ``if` `(l.l1 !``=` `-``1` `and` `r.r1 !``=` `-``1``):``        ``x.max1 ``=` `max``(x.max1, r.r1 ``-` `l.l1)` `    ``return` `x` `# utility function``# for updating a node``def` `UpdateUtil(x: node) ``-``> node:``    ``x.l0, x.l1 ``=` `x.l1, x.l0``    ``x.r0, x.r1 ``=` `x.r1, x.r0``    ``x.min1, x.min0 ``=` `x.min0, x.min1``    ``x.max0, x.max1 ``=` `x.max1, x.max0` `    ``return` `x` `# A recursive function that constructs``# Segment Tree for given string``def` `Build(qs: ``int``, qe: ``int``, ind: ``int``, arr: ``List``[``int``]) ``-``> ``None``:` `  ``# If start is equal to end then``    ``# insert the array element``    ``if` `(qs ``=``=` `qe):``        ``if` `(arr[qs] ``=``=` `1``):``            ``seg[ind].l1 ``=` `seg[ind].r1 ``=` `qs``        ``else``:``            ``seg[ind].l0 ``=` `seg[ind].r0 ``=` `qs` `        ``lazy[ind] ``=` `0``        ``return` `    ``mid ``=` `(qs ``+` `qe) >> ``1` `    ``# Build the segment tree``    ``# for range qs to mid``    ``Build(qs, mid, ind << ``1``, arr)` `    ``# Build the segment tree``    ``# for range mid+1 to qe``    ``Build(mid ``+` `1``, qe, ind << ``1` `| ``1``, arr)` `    ``# merge the two child nodes``    ``# to obtain the parent node``    ``seg[ind] ``=` `MergeUtil(seg[ind << ``1``], seg[ind << ``1` `| ``1``])` `# Query in a range qs to qe``def` `Query(qs: ``int``, qe: ``int``, ns: ``int``, ne: ``int``, ind: ``int``) ``-``> node:``    ``if` `(lazy[ind] !``=` `0``):``        ``seg[ind] ``=` `UpdateUtil(seg[ind])``        ``if` `(ns !``=` `ne):``            ``lazy[ind ``*` `2``] ^``=` `lazy[ind]``            ``lazy[ind ``*` `2` `+` `1``] ^``=` `lazy[ind]``        ``lazy[ind] ``=` `0``    ``x ``=` `node()` `    ``# If the range lies in this segment``    ``if` `(qs <``=` `ns ``and` `qe >``=` `ne):``        ``return` `seg[ind]` `    ``# If the range is out of the bounds``    ``# of this segment``    ``if` `(ne < qs ``or` `ns > qe ``or` `ns > ne):``        ``return` `x` `    ``# Else query for the right and left``    ``# child node of this subtree``    ``# and merge them``    ``mid ``=` `(ns ``+` `ne) >> ``1``    ``l ``=` `Query(qs, qe, ns, mid, ind << ``1``)``    ``r ``=` `Query(qs, qe, mid ``+` `1``, ne, ind << ``1` `| ``1``)``    ``x ``=` `MergeUtil(l, r)``    ``return` `x` `# range update using lazy prpagation``def` `RangeUpdate(us: ``int``, ue: ``int``, ns: ``int``, ne: ``int``, ind: ``int``) ``-``> ``None``:``    ``if` `(lazy[ind] !``=` `0``):``        ``seg[ind] ``=` `UpdateUtil(seg[ind])``        ``if` `(ns !``=` `ne):``            ``lazy[ind ``*` `2``] ^``=` `lazy[ind]``            ``lazy[ind ``*` `2` `+` `1``] ^``=` `lazy[ind]``        ``lazy[ind] ``=` `0` `    ``# If the range is out of the bounds``    ``# of this segment``    ``if` `(ns > ne ``or` `ns > ue ``or` `ne < us):``        ``return` `    ``# If the range lies in this segment``    ``if` `(ns >``=` `us ``and` `ne <``=` `ue):``        ``seg[ind] ``=` `UpdateUtil(seg[ind])``        ``if` `(ns !``=` `ne):``            ``lazy[ind ``*` `2``] ^``=` `1``            ``lazy[ind ``*` `2` `+` `1``] ^``=` `1``        ``return` `    ``# Else query for the right and left``    ``# child node of this subtree``    ``# and merge them``    ``mid ``=` `(ns ``+` `ne) >> ``1``    ``RangeUpdate(us, ue, ns, mid, ind << ``1``)``    ``RangeUpdate(us, ue, mid ``+` `1``, ne, ind << ``1` `| ``1``)``    ``l ``=` `seg[ind << ``1``]``    ``r ``=` `seg[ind << ``1` `| ``1``]``    ``seg[ind] ``=` `MergeUtil(l, r)` `# Driver code``if` `__name__ ``=``=` `"__main__"``:``    ``arr ``=` `[``1``, ``1``, ``0``, ``1``, ``0``, ``1``, ``0``, ``1``, ``0``, ``1``, ``0``, ``1``, ``1``, ``0``]``    ``n ``=` `len``(arr)` `    ``# Build the segment tree``    ``Build(``0``, n ``-` `1``, ``1``, arr)` `    ``# Query of Type 2 in the range 3 to 7``    ``ans ``=` `Query(``3``, ``7``, ``0``, n ``-` `1``, ``1``)``    ``print``(ans.min1)` `    ``# Query of Type 3 in the range 2 to 5``    ``ans ``=` `Query(``2``, ``5``, ``0``, n ``-` `1``, ``1``)``    ``print``(ans.max1)` `    ``# Query of Type 1 in the range 1 to 4``    ``RangeUpdate(``1``, ``4``, ``0``, n ``-` `1``, ``1``)` `    ``# Query of Type 4 in the range 3 to 7``    ``ans ``=` `Query(``3``, ``7``, ``0``, n ``-` `1``, ``1``)``    ``print``(ans.min0)` `    ``# Query of Type 5 in the range 4 to 9``    ``ans ``=` `Query(``4``, ``9``, ``0``, n ``-` `1``, ``1``)``    ``print``(ans.max0)` `# This code is contributed by sanjeev2552`
Output:
```2
2
3
2```

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with experts, please refer DSA Live Classes for Working Professionals and Competitive Programming Live for Students.

My Personal Notes arrow_drop_up