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:
// 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;
} |
// 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. |
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__ |
// 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__ |
// 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:
// 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 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. |
# 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# 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. |
<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)