Open In App

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

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.




// 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).



       0 xor 1 = 1
       1 xor 1 = 0
       l0 and l1 will get swapped
       r0 and r1 will get swapped
       min0 and min1 will get swapped
       max0 and max1 will get swapped

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>

Output
2
2
3
2

Time Complexity: O(n*log(n))
Auxiliary Space: O(n)


Article Tags :