Open In App

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

Last Updated : 04 Apr, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

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>


Output

2
2
3
2

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



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads