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.
- 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}.
- 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; } |
Java
// 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 = new node(); if (left.l0 != null ) 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 = Math.min(left.min0,right.min0); if (left.r0 != null and right.l0 != null ) cur.min0 = Math.min(cur.min0 , (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; } // This code is contributed by aadityaburujwale. |
Python3
def Merge(left, right): cur = {} if left[ 'l0' ]: cur[ 'l0' ] = left[ 'l0' ] else : cur[ 'l0' ] = right[ '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' ] = min (left[ 'min0' ], right[ 'min0' ]) if left[ 'r0' ] and right[ 'l0' ]: cur[ 'min0' ] = min (cur[ 'min0' ], 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 # This code is contributed by akashish__ |
C#
// 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. public Node Merge(Node left, Node right) { Node cur = new Node(); if (left.l0 != null ) cur.l0 = left.l0; else cur.l0 = right.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 = Math.Min(left.min0, right.min0); if (left.r0 != null && right.l0 != null ) cur.min0 = Math.Min(cur.min0, (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; } // This code is contributed by akashish__ |
Javascript
// 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. function Merge(left, right) { let cur = {}; if (left.l0) { cur.l0 = left.l0; } else { cur.l0 = right.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 = Math.min(left.min0, right.min0); if (left.r0 && right.l0) { cur.min0 = Math.min(cur.min0, 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; } // contributed by akashish__ |
The time and space complexity of the above code is O(1).
- 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
- 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
- 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 <bits/stdc++.h> using namespace std; int lazy[100001]; // 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[100001]; // 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 propagation 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[0]); // 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; } |
Java
// java code addition import java.io.*; import java.util.Arrays; class Node { int l1, r1, l0, r0; int min0, max0, min1, max1; public Node() { l1 = r1 = l0 = r0 = - 1 ; max1 = max0 = Integer.MIN_VALUE; min1 = min0 = Integer.MAX_VALUE; } } class LazyPropagationSegmentTree { static final int MAX = 100001 ; static int [] lazy = new int [MAX]; static Node[] seg = new Node[MAX]; public static Node MergeUtil(Node l, Node r) { Node x = new Node(); 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 = Math.min(l.min0, r.min0); if (l.r0 != - 1 && r.l0 != - 1 ) x.min0 = Math.min(x.min0, r.l0 - l.r0); x.min1 = Math.min(l.min1, r.min1); if (l.r1 != - 1 && r.l1 != - 1 ) x.min1 = Math.min(x.min1, r.l1 - l.r1); x.max0 = Math.max(l.max0, r.max0); if (l.l0 != - 1 && r.r0 != - 1 ) x.max0 = Math.max(x.max0, r.r0 - l.l0); x.max1 = Math.max(l.max1, r.max1); if (l.l1 != - 1 && r.r1 != - 1 ) x.max1 = Math.max(x.max1, r.r1 - l.l1); return x; } public static Node UpdateUtil(Node x) { int temp; temp = x.l0; x.l0 = x.l1; x.l1 = temp; temp = x.r0; x.r0 = x.r1; x.r1 = temp; temp = x.min0; x.min0 = x.min1; x.min1 = temp; temp = x.max0; x.max0 = x.max1; x.max1 = temp; return x; } public static void Build( int qs, int qe, int ind, int [] arr) { 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(qs, mid, ind << 1 , arr); Build(mid + 1 , qe, ind << 1 | 1 , arr); seg[ind] = MergeUtil(seg[ind << 1 ], seg[ind << 1 | 1 ]); } public static 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 = new Node(); // 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 propagation public static 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 public static void main(String[] args) { // Initialising segment for ( int i = 0 ; i < 100001 ; i++){ seg[i] = new Node(); } int [] arr = { 1 , 1 , 0 , 1 , 0 , 1 , 0 , 1 , 0 , 1 , 0 , 1 , 1 , 0 }; int n = arr.length; // Build the segment tree // Console.WriteLine("HI"); Build( 0 , n - 1 , 1 , arr); // Console.WriteLine("HI2"); // Query of Type 2 in the range 3 to 7 Node ans = Query( 3 , 7 , 0 , n - 1 , 1 ); System.out.println(ans.min1); // Query of Type 3 in the range 2 to 5 ans = Query( 2 , 5 , 0 , n - 1 , 1 ); System.out.println(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 ); System.out.println(ans.min0); // Query of Type 5 in the range 4 to 9 ans = Query( 4 , 9 , 0 , n - 1 , 1 ); System.out.println(ans.max0); } } // The code is contributed by Nidhi goel. |
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 propagation 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 |
C#
// C# code addition using System; using System.Collections; using System.Collections.Generic; using System.Linq; // Class for each node in the segment tree class Node { public int l1, r1, l0, r0; public int min0, max0, min1, max1; public Node() { l1 = r1 = l0 = r0 = -1; max1 = max0 = int .MinValue; min1 = min0 = int .MaxValue; } } class LazyPropagationSegmentTree { public static int MAX = 100001; public static int [] lazy = new int [MAX]; public static Node[] seg = new Node[MAX]; // A utility function for merging two nodes public static Node MergeUtil(Node l, Node r) { Node x = new Node(); 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 = Math.Min(l.min0, r.min0); if (l.r0 != -1 && r.l0 != -1) x.min0 = Math.Min(x.min0, r.l0 - l.r0); x.min1 = Math.Min(l.min1, r.min1); if (l.r1 != -1 && r.l1 != -1) x.min1 = Math.Min(x.min1, r.l1 - l.r1); x.max0 = Math.Max(l.max0, r.max0); if (l.l0 != -1 && r.r0 != -1) x.max0 = Math.Max(x.max0, r.r0 - l.l0); x.max1 = Math.Max(l.max1, r.max1); if (l.l1 != -1 && r.r1 != -1) x.max1 = Math.Max(x.max1, r.r1 - l.l1); return x; } // A utility function for updating a node public static Node UpdateUtil(Node x) { int temp; temp = x.l0; x.l0 = x.l1; x.l1 = temp; temp = x.r0; x.r0 = x.r1; x.r1 = temp; temp = x.min0; x.min0 = x.min1; x.min1 = temp; temp = x.max0; x.max0 = x.max1; x.max1 = temp; return x; } // A recursive function that constructs // Segment Tree for given string public static void Build( int qs, int qe, int ind, int [] arr) { // If start is equal to end then // insert the array element // Console.WriteLine(ind); 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 public static 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 = new Node(); // 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 propagation public static 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 static void Main() { // Initialising segment for ( int i = 0; i < 100001; i++){ seg[i] = new Node(); } int [] arr = { 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0 }; int n = arr.Length; // Build the segment tree // Console.WriteLine("HI"); Build(0, n - 1, 1, arr); // Console.WriteLine("HI2"); // Query of Type 2 in the range 3 to 7 Node ans = Query(3, 7, 0, n - 1, 1); Console.WriteLine(ans.min1); // Query of Type 3 in the range 2 to 5 ans = Query(2, 5, 0, n - 1, 1); Console.WriteLine(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); Console.WriteLine(ans.min0); // Query of Type 5 in the range 4 to 9 ans = Query(4, 9, 0, n - 1, 1); Console.WriteLine(ans.max0); } } // The code is contributed by Nidhi goel. |
Javascript
<script> // javascript program for the given problem // Class for each node // in the segment tree class node { constructor() { this .l1 = this .r1 = this .l0 = this .r0 = -1; this .max1 = this .max0 = -2000; this .min1 = this .min0 = 2000; } } let seg = new Array(100001); for (let i = 0; i < 100001; i++){ seg[i] = new node(); } let lazy = new Array(100001); // A utility function for // merging two nodes function MergeUtil(l, r) { let x = new node(); 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 = Math.min(l.min0, r.min0); if (l.r0 != -1 && r.l0 != -1) x.min0 = Math.min(x.min0, r.l0 - l.r0); x.min1 = Math.min(l.min1, r.min1); if (l.r1 != -1 && r.l1 != -1) x.min1 = Math.min(x.min1, r.l1 - l.r1); x.max0 = Math.max(l.max0, r.max0); if (l.l0 != -1 && r.r0 != -1) x.max0 = Math.max(x.max0, r.r0 - l.l0); x.max1 = Math.max(l.max1, r.max1); if (l.l1 != -1 && r.r1 != -1) x.max1 = Math.max(x.max1, r.r1 - l.l1); return x; } // utility function // for updating a node function UpdateUtil(x) { // swap l0, and l1 let temp = x.l0; x.l0 = x.l1; x.l1 = temp; // swap l0, and l1 temp = x.r0; x.r0 = x.r1; x.r1 = temp; // swap l0, and l1 temp = x.min0; x.min0 = x.min1; x.min1 = temp; // swap max0, and max1 temp = x.max0; x.max0 = x.max1; x.max1 = temp; return x; } // A recursive function that constructs // Segment Tree for given string function Build(qs, qe, ind, 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 ; } let 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 function Query(qs, qe, ns, ne, 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; } let x = new node(); // 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 let mid = (ns + ne) >> 1; let l = Query(qs, qe, ns, mid, ind << 1); let r = Query(qs, qe, mid + 1, ne, ind << 1 | 1); x = MergeUtil(l, r); return x; } // range update using lazy propagation function RangeUpdate(us, ue, ns, ne, 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 let mid = (ns + ne) >> 1; RangeUpdate(us, ue, ns, mid, ind << 1); RangeUpdate(us, ue, mid + 1, ne, ind << 1 | 1); let l = seg[ind << 1], r = seg[ind << 1 | 1]; seg[ind] = MergeUtil(l, r); } // Driver code let arr = [1, 1, 0, 1, 0, 1, 0, 1, 0,1, 0, 1,1, 0 ]; let n = arr.length; // Build the segment tree Build(0, n - 1, 1, arr); // Query of Type 2 in the range 3 to 7 let ans = Query(3, 7, 0, n - 1, 1); document.write(ans.min1 + 1); // Query of Type 3 in the range 2 to 5 ans = Query(2, 5, 0, n - 1, 1); document.write(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); document.write(ans.min0); // Query of Type 5 in the range 4 to 9 ans = Query(4, 9, 0, n - 1, 1); document.write(ans.max0); // The code is contributed by Nidhi goel. </script> |
2 2 3 2
Time Complexity: O(n*log(n))
Auxiliary Space: O(n)
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!