Given an array of size N initially filled with 0s. There are Q queries to be performed, and each query can be one of two types:
- Type 1 (1, L, R, X): Add X to all elements in the segment from L to R−1.
- Type 2 (2, L, R): Find the minimum value in the segment from L to R−1.
Example:
Input: n = 5, q = 6, queries = {
{1, 0, 3, 3},
{2, 1, 2},
{1, 1, 4, 4},
{2, 1, 3},
{2, 1, 4},
{2, 3, 5} }
Output:
3
7
4
0
Approach:
The idea is to use Segment Tree with Lazy Propagation. It’s used to efficiently perform range update and range query operations on an array.
- The build function constructs the segment tree from the input array.
- The update function updates a range of values in the array and marks nodes for lazy updates.
- The query function finds the minimum value in a range, taking into account any pending lazy updates.
Steps-by-step approach:
- Define constants for the maximum size of the array and the segment tree.
- Create a function to build the segment tree recursively.
- Create a function to update a range in the array with lazy propagation.
- Create a function to query a range in the array with lazy propagation.
- In the main function:
- Build the initial segment tree with zeros.
- Define queries as a vector of vectors.
- For each query:
- If it's a type 1 query, update the array using lazy propagation.
- If it's a type 2 query, query the array and print the result.
Below is the implementation of the above approach:
#include<bits/stdc++.h>
using namespace std;
const int MAX = 1e5; // Max size of array
int tree[4*MAX]; // Segment tree
int lazy[4*MAX]; // Lazy array to propagate updates
// Function to build the tree
void build(int node, int start, int end)
{
if(start == end)
{
// Leaf node will have a single element
tree[node] = 0;
}
else
{
int mid = (start + end) / 2;
// Recur for the 2 children
build(2*node, start, mid);
build(2*node+1, mid+1, end);
// Internal node will have the minimum of both of its children
tree[node] = min(tree[2*node], tree[2*node+1]);
}
}
// Function to update a node
void update(int node, int start, int end, int l, int r, int val)
{
if(lazy[node] != 0)
{
// This node needs to be updated
tree[node] += lazy[node]; // Update it
if(start != end)
{
lazy[node*2] += lazy[node]; // Mark child as lazy
lazy[node*2+1] += lazy[node]; // Mark child as lazy
}
lazy[node] = 0; // Reset it
}
if(start > end or start > r or end < l) return; // Current segment is not within range [l, r]
if(start >= l and end <= r)
{
// Segment is fully within range
tree[node] += val;
if(start != end)
{
// Not leaf node
lazy[node*2] += val;
lazy[node*2+1] += val;
}
return;
}
int mid = (start + end) / 2;
update(node*2, start, mid, l, r, val); // Updating left child
update(node*2 + 1, mid + 1, end, l, r, val); // Updating right child
tree[node] = min(tree[node*2], tree[node*2+1]); // Updating root with min value
}
// Function to query the tree
int query(int node, int start, int end, int l, int r)
{
if(start > end or start > r or end < l) return MAX; // Out of range
if(lazy[node] != 0)
{
// This node needs to be updated
tree[node] += lazy[node]; // Update it
if(start != end)
{
lazy[node*2] += lazy[node]; // Mark child as lazy
lazy[node*2+1] += lazy[node]; // Mark child as lazy
}
lazy[node] = 0; // Reset it
}
if(start >= l and end <= r) // Current segment is totally within range [l, r]
return tree[node];
int mid = (start + end) / 2;
int p1 = query(node*2, start, mid, l, r); // Query left child
int p2 = query(node*2 + 1, mid + 1, end, l, r); // Query right child
return min(p1, p2);
}
int main()
{
int n = 5;
build(1, 0, n-1);
// Define the queries
vector<vector<int>> queries = {
{1, 0, 3, 3},
{2, 1, 2},
{1, 1, 4, 4},
{2, 1, 3},
{2, 1, 4},
{2, 3, 5}
};
for(auto &q : queries)
{
int type = q[0];
if(type == 1)
{
int l = q[1], r = q[2], x = q[3];
update(1, 0, n-1, l, r-1, x); // Update the array
}
else if(type == 2)
{
int l = q[1], r = q[2];
int ans = query(1, 0, n-1, l, r-1); // Query the array
cout << ans << endl;
}
}
return 0;
}
import java.util.*;
public class SegmentTree {
static final int MAX = 100000; // Max size of array
static int[] tree = new int[4 * MAX]; // Segment tree
static int[] lazy = new int[4 * MAX]; // Lazy array to propagate updates
// Function to build the tree
static void build(int node, int start, int end) {
if (start == end) {
// Leaf node will have a single element
tree[node] = 0;
} else {
int mid = (start + end) / 2;
// Recur for the 2 children
build(2 * node, start, mid);
build(2 * node + 1, mid + 1, end);
// Internal node will have the minimum of both of its children
tree[node] = Math.min(tree[2 * node], tree[2 * node + 1]);
}
}
// Function to update a node
static void update(int node, int start, int end, int l, int r, int val) {
if (lazy[node] != 0) {
// This node needs to be updated
tree[node] += lazy[node]; // Update it
if (start != end) {
lazy[node * 2] += lazy[node]; // Mark left child as lazy
lazy[node * 2 + 1] += lazy[node]; // Mark right child as lazy
}
lazy[node] = 0; // Reset it
}
if (start > end || start > r || end < l)
return; // Current segment is not within range [l, r]
if (start >= l && end <= r) {
// Segment is fully within range
tree[node] += val;
if (start != end) {
// Not leaf node
lazy[node * 2] += val;
lazy[node * 2 + 1] += val;
}
return;
}
int mid = (start + end) / 2;
update(node * 2, start, mid, l, r, val); // Updating left child
update(node * 2 + 1, mid + 1, end, l, r, val); // Updating right child
tree[node] = Math.min(tree[node * 2], tree[node * 2 + 1]); // Updating root with min value
}
// Function to query the tree
static int query(int node, int start, int end, int l, int r) {
if (start > end || start > r || end < l)
return MAX; // Out of range
if (lazy[node] != 0) {
// This node needs to be updated
tree[node] += lazy[node]; // Update it
if (start != end) {
lazy[node * 2] += lazy[node]; // Mark left child as lazy
lazy[node * 2 + 1] += lazy[node]; // Mark right child as lazy
}
lazy[node] = 0; // Reset it
}
if (start >= l && end <= r)
return tree[node]; // Current segment is totally within range [l, r]
int mid = (start + end) / 2;
int p1 = query(node * 2, start, mid, l, r); // Query left child
int p2 = query(node * 2 + 1, mid + 1, end, l, r); // Query right child
return Math.min(p1, p2);
}
public static void main(String[] args) {
int n = 5;
build(1, 0, n - 1);
// Define the queries
List<int[]> queries = Arrays.asList(
new int[]{1, 0, 3, 3},
new int[]{2, 1, 2},
new int[]{1, 1, 4, 4},
new int[]{2, 1, 3},
new int[]{2, 1, 4},
new int[]{2, 3, 5}
);
for (int[] q : queries) {
int type = q[0];
if (type == 1) {
int l = q[1], r = q[2], x = q[3];
update(1, 0, n - 1, l, r - 1, x); // Update the array
} else if (type == 2) {
int l = q[1], r = q[2];
int ans = query(1, 0, n - 1, l, r - 1); // Query the array
System.out.println(ans);
}
}
}
}
using System;
using System.Collections.Generic;
class SegmentTree
{
const int MAX = 100000; // Max size of array
int[] tree = new int[4 * MAX]; // Segment tree
int[] lazy = new int[4 * MAX]; // Lazy array to propagate updates
// Function to build the tree
void Build(int node, int start, int end)
{
if (start == end)
{
// Leaf node will have a single element
tree[node] = 0;
}
else
{
int mid = (start + end) / 2;
// Recur for the 2 children
Build(2 * node, start, mid);
Build(2 * node + 1, mid + 1, end);
// Internal node will have the minimum of both of its children
tree[node] = Math.Min(tree[2 * node], tree[2 * node + 1]);
}
}
// Function to update a node
void Update(int node, int start, int end, int l, int r, int val)
{
if (lazy[node] != 0)
{
// This node needs to be updated
tree[node] += lazy[node]; // Update it
if (start != end)
{
lazy[node * 2] += lazy[node]; // Mark child as lazy
lazy[node * 2 + 1] += lazy[node]; // Mark child as lazy
}
lazy[node] = 0; // Reset it
}
if (start > end || start > r || end < l) return; // Current segment is not within range [l, r]
if (start >= l && end <= r)
{
// Segment is fully within range
tree[node] += val;
if (start != end)
{
// Not a leaf node
lazy[node * 2] += val;
lazy[node * 2 + 1] += val;
}
return;
}
int mid = (start + end) / 2;
Update(node * 2, start, mid, l, r, val); // Updating left child
Update(node * 2 + 1, mid + 1, end, l, r, val); // Updating right child
tree[node] = Math.Min(tree[node * 2], tree[node * 2 + 1]); // Updating root with min value
}
// Function to query the tree
int Query(int node, int start, int end, int l, int r)
{
if (start > end || start > r || end < l) return int.MaxValue; // Out of range
if (lazy[node] != 0)
{
// This node needs to be updated
tree[node] += lazy[node]; // Update it
if (start != end)
{
lazy[node * 2] += lazy[node]; // Mark child as lazy
lazy[node * 2 + 1] += lazy[node]; // Mark child as lazy
}
lazy[node] = 0; // Reset it
}
if (start >= l && end <= r) // Current segment is totally within range [l, r]
return tree[node];
int mid = (start + end) / 2;
int p1 = Query(node * 2, start, mid, l, r); // Query left child
int p2 = Query(node * 2 + 1, mid + 1, end, l, r); // Query right child
return Math.Min(p1, p2);
}
static void Main()
{
int n = 5;
var segmentTree = new SegmentTree();
segmentTree.Build(1, 0, n - 1);
// Define the queries
var queries = new List<int[]>()
{
new int[] {1, 0, 3, 3},
new int[] {2, 1, 2},
new int[] {1, 1, 4, 4},
new int[] {2, 1, 3},
new int[] {2, 1, 4},
new int[] {2, 3, 5}
};
foreach (var q in queries)
{
int type = q[0];
if (type == 1)
{
int l = q[1], r = q[2], x = q[3];
segmentTree.Update(1, 0, n - 1, l, r - 1, x); // Update the array
}
else if (type == 2)
{
int l = q[1], r = q[2];
int ans = segmentTree.Query(1, 0, n - 1, l, r - 1); // Query the array
Console.WriteLine(ans);
}
}
}
}
const MAX = 1e5; // Max size of array
let tree = new Array(4*MAX).fill(0); // Segment tree
let lazy = new Array(4*MAX).fill(0); // Lazy array to propagate updates
// Function to build the tree
function build(node, start, end) {
if(start === end) {
// Leaf node will have a single element
tree[node] = 0;
} else {
let mid = Math.floor((start + end) / 2);
// Recur for the 2 children
build(2*node, start, mid);
build(2*node+1, mid+1, end);
// Internal node will have the minimum of both of its children
tree[node] = Math.min(tree[2*node], tree[2*node+1]);
}
}
// Function to update a node
function update(node, start, end, l, r, val) {
if(lazy[node] !== 0) {
// This node needs to be updated
tree[node] += lazy[node]; // Update it
if(start !== end) {
lazy[node*2] += lazy[node]; // Mark child as lazy
lazy[node*2+1] += lazy[node]; // Mark child as lazy
}
lazy[node] = 0; // Reset it
}
if(start > end || start > r || end < l) return; // Current segment is not within range [l, r]
if(start >= l && end <= r) {
// Segment is fully within range
tree[node] += val;
if(start !== end) {
// Not leaf node
lazy[node*2] += val;
lazy[node*2+1] += val;
}
return;
}
let mid = Math.floor((start + end) / 2);
update(node*2, start, mid, l, r, val); // Updating left child
update(node*2 + 1, mid + 1, end, l, r, val); // Updating right child
tree[node] = Math.min(tree[node*2], tree[node*2+1]); // Updating root with min value
}
// Function to query the tree
function query(node, start, end, l, r) {
if(start > end || start > r || end < l) return MAX; // Out of range
if(lazy[node] !== 0) {
// This node needs to be updated
tree[node] += lazy[node]; // Update it
if(start !== end) {
lazy[node*2] += lazy[node]; // Mark child as lazy
lazy[node*2+1] += lazy[node]; // Mark child as lazy
}
lazy[node] = 0; // Reset it
}
if(start >= l && end <= r) // Current segment is totally within range [l, r]
return tree[node];
let mid = Math.floor((start + end) / 2);
let p1 = query(node*2, start, mid, l, r); // Query left child
let p2 = query(node*2 + 1, mid + 1, end, l, r); // Query right child
return Math.min(p1, p2);
}
// Main function
function main() {
let n = 5;
build(1, 0, n-1);
// Define the queries
let queries = [
[1, 0, 3, 3],
[2, 1, 2],
[1, 1, 4, 4],
[2, 1, 3],
[2, 1, 4],
[2, 3, 5]
];
for(let q of queries) {
let type = q[0];
if(type === 1) {
let l = q[1], r = q[2], x = q[3];
update(1, 0, n-1, l, r-1, x); // Update the array
} else if(type === 2) {
let l = q[1], r = q[2];
let ans = query(1, 0, n-1, l, r-1); // Query the array
console.log(ans);
}
}
}
main();
MAX = int(1e5) # Max size of array
tree = [0] * (4 * MAX) # Segment tree
lazy = [0] * (4 * MAX) # Lazy array to propagate updates
# Function to build the tree
def build(node, start, end):
if start == end:
# Leaf node will have a single element
tree[node] = 0
else:
mid = (start + end) // 2
# Recur for the 2 children
build(2 * node, start, mid)
build(2 * node + 1, mid + 1, end)
# Internal node will have the minimum of both of its children
tree[node] = min(tree[2 * node], tree[2 * node + 1])
# Function to update a node
def update(node, start, end, l, r, val):
if lazy[node] != 0:
# This node needs to be updated
tree[node] += lazy[node] # Update it
if start != end:
lazy[node * 2] += lazy[node] # Mark child as lazy
lazy[node * 2 + 1] += lazy[node] # Mark child as lazy
lazy[node] = 0 # Reset it
if start > end or start > r or end < l:
return # Current segment is not within range [l, r]
if start >= l and end <= r:
# Segment is fully within range
tree[node] += val
if start != end:
# Not leaf node
lazy[node * 2] += val
lazy[node * 2 + 1] += val
return
mid = (start + end) // 2
update(node * 2, start, mid, l, r, val) # Updating left child
update(node * 2 + 1, mid + 1, end, l, r, val) # Updating right child
tree[node] = min(tree[node * 2], tree[node * 2 + 1]) # Updating root with min value
# Function to query the tree
def query(node, start, end, l, r):
if start > end or start > r or end < l:
return MAX # Out of range
if lazy[node] != 0:
# This node needs to be updated
tree[node] += lazy[node] # Update it
if start != end:
lazy[node * 2] += lazy[node] # Mark child as lazy
lazy[node * 2 + 1] += lazy[node] # Mark child as lazy
lazy[node] = 0 # Reset it
if start >= l and end <= r: # Current segment is totally within range [l, r]
return tree[node]
mid = (start + end) // 2
p1 = query(node * 2, start, mid, l, r) # Query left child
p2 = query(node * 2 + 1, mid + 1, end, l, r) # Query right child
return min(p1, p2)
# Main function
def main():
n = 5
build(1, 0, n - 1)
# Define the queries
queries = [
[1, 0, 3, 3],
[2, 1, 2],
[1, 1, 4, 4],
[2, 1, 3],
[2, 1, 4],
[2, 3, 5]
]
for q in queries:
type = q[0]
if type == 1:
l, r, x = q[1], q[2], q[3]
update(1, 0, n - 1, l, r - 1, x) # Update the array
elif type == 2:
l, r = q[1], q[2]
ans = query(1, 0, n - 1, l, r - 1) # Query the array
print(ans)
main()
Output
3 7 4 0
Time Complexity: O(log n) per query and update, O(n) for the construction of the segment tree.
Auxiliary Space : O(n) for the segment tree.