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:
C++
#include<bits/stdc++.h>
using namespace std;
const int MAX = 1e5;
int tree[4*MAX];
int lazy[4*MAX];
void build( int node, int start, int end)
{
if (start == end)
{
tree[node] = 0;
}
else
{
int mid = (start + end) / 2;
build(2*node, start, mid);
build(2*node+1, mid+1, end);
tree[node] = min(tree[2*node], tree[2*node+1]);
}
}
void update( int node, int start, int end, int l, int r, int val)
{
if (lazy[node] != 0)
{
tree[node] += lazy[node];
if (start != end)
{
lazy[node*2] += lazy[node];
lazy[node*2+1] += lazy[node];
}
lazy[node] = 0;
}
if (start > end or start > r or end < l) return ;
if (start >= l and end <= r)
{
tree[node] += val;
if (start != end)
{
lazy[node*2] += val;
lazy[node*2+1] += val;
}
return ;
}
int mid = (start + end) / 2;
update(node*2, start, mid, l, r, val);
update(node*2 + 1, mid + 1, end, l, r, val);
tree[node] = min(tree[node*2], tree[node*2+1]);
}
int query( int node, int start, int end, int l, int r)
{
if (start > end or start > r or end < l) return MAX;
if (lazy[node] != 0)
{
tree[node] += lazy[node];
if (start != end)
{
lazy[node*2] += lazy[node];
lazy[node*2+1] += lazy[node];
}
lazy[node] = 0;
}
if (start >= l and end <= r)
return tree[node];
int mid = (start + end) / 2;
int p1 = query(node*2, start, mid, l, r);
int p2 = query(node*2 + 1, mid + 1, end, l, r);
return min(p1, p2);
}
int main()
{
int n = 5;
build(1, 0, n-1);
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);
}
else if (type == 2)
{
int l = q[1], r = q[2];
int ans = query(1, 0, n-1, l, r-1);
cout << ans << endl;
}
}
return 0;
}
|
Java
import java.util.*;
public class SegmentTree {
static final int MAX = 100000 ;
static int [] tree = new int [ 4 * MAX];
static int [] lazy = new int [ 4 * MAX];
static void build( int node, int start, int end) {
if (start == end) {
tree[node] = 0 ;
} else {
int mid = (start + end) / 2 ;
build( 2 * node, start, mid);
build( 2 * node + 1 , mid + 1 , end);
tree[node] = Math.min(tree[ 2 * node], tree[ 2 * node + 1 ]);
}
}
static void update( int node, int start, int end, int l, int r, int val) {
if (lazy[node] != 0 ) {
tree[node] += lazy[node];
if (start != end) {
lazy[node * 2 ] += lazy[node];
lazy[node * 2 + 1 ] += lazy[node];
}
lazy[node] = 0 ;
}
if (start > end || start > r || end < l)
return ;
if (start >= l && end <= r) {
tree[node] += val;
if (start != end) {
lazy[node * 2 ] += val;
lazy[node * 2 + 1 ] += val;
}
return ;
}
int mid = (start + end) / 2 ;
update(node * 2 , start, mid, l, r, val);
update(node * 2 + 1 , mid + 1 , end, l, r, val);
tree[node] = Math.min(tree[node * 2 ], tree[node * 2 + 1 ]);
}
static int query( int node, int start, int end, int l, int r) {
if (start > end || start > r || end < l)
return MAX;
if (lazy[node] != 0 ) {
tree[node] += lazy[node];
if (start != end) {
lazy[node * 2 ] += lazy[node];
lazy[node * 2 + 1 ] += lazy[node];
}
lazy[node] = 0 ;
}
if (start >= l && end <= r)
return tree[node];
int mid = (start + end) / 2 ;
int p1 = query(node * 2 , start, mid, l, r);
int p2 = query(node * 2 + 1 , mid + 1 , end, l, r);
return Math.min(p1, p2);
}
public static void main(String[] args) {
int n = 5 ;
build( 1 , 0 , n - 1 );
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);
} else if (type == 2 ) {
int l = q[ 1 ], r = q[ 2 ];
int ans = query( 1 , 0 , n - 1 , l, r - 1 );
System.out.println(ans);
}
}
}
}
|
C#
using System;
using System.Collections.Generic;
class SegmentTree
{
const int MAX = 100000;
int [] tree = new int [4 * MAX];
int [] lazy = new int [4 * MAX];
void Build( int node, int start, int end)
{
if (start == end)
{
tree[node] = 0;
}
else
{
int mid = (start + end) / 2;
Build(2 * node, start, mid);
Build(2 * node + 1, mid + 1, end);
tree[node] = Math.Min(tree[2 * node], tree[2 * node + 1]);
}
}
void Update( int node, int start, int end, int l, int r, int val)
{
if (lazy[node] != 0)
{
tree[node] += lazy[node];
if (start != end)
{
lazy[node * 2] += lazy[node];
lazy[node * 2 + 1] += lazy[node];
}
lazy[node] = 0;
}
if (start > end || start > r || end < l) return ;
if (start >= l && end <= r)
{
tree[node] += val;
if (start != end)
{
lazy[node * 2] += val;
lazy[node * 2 + 1] += val;
}
return ;
}
int mid = (start + end) / 2;
Update(node * 2, start, mid, l, r, val);
Update(node * 2 + 1, mid + 1, end, l, r, val);
tree[node] = Math.Min(tree[node * 2], tree[node * 2 + 1]);
}
int Query( int node, int start, int end, int l, int r)
{
if (start > end || start > r || end < l) return int .MaxValue;
if (lazy[node] != 0)
{
tree[node] += lazy[node];
if (start != end)
{
lazy[node * 2] += lazy[node];
lazy[node * 2 + 1] += lazy[node];
}
lazy[node] = 0;
}
if (start >= l && end <= r)
return tree[node];
int mid = (start + end) / 2;
int p1 = Query(node * 2, start, mid, l, r);
int p2 = Query(node * 2 + 1, mid + 1, end, l, r);
return Math.Min(p1, p2);
}
static void Main()
{
int n = 5;
var segmentTree = new SegmentTree();
segmentTree.Build(1, 0, n - 1);
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);
}
else if (type == 2)
{
int l = q[1], r = q[2];
int ans = segmentTree.Query(1, 0, n - 1, l, r - 1);
Console.WriteLine(ans);
}
}
}
}
|
Javascript
const MAX = 1e5;
let tree = new Array(4*MAX).fill(0);
let lazy = new Array(4*MAX).fill(0);
function build(node, start, end) {
if (start === end) {
tree[node] = 0;
} else {
let mid = Math.floor((start + end) / 2);
build(2*node, start, mid);
build(2*node+1, mid+1, end);
tree[node] = Math.min(tree[2*node], tree[2*node+1]);
}
}
function update(node, start, end, l, r, val) {
if (lazy[node] !== 0) {
tree[node] += lazy[node];
if (start !== end) {
lazy[node*2] += lazy[node];
lazy[node*2+1] += lazy[node];
}
lazy[node] = 0;
}
if (start > end || start > r || end < l) return ;
if (start >= l && end <= r) {
tree[node] += val;
if (start !== end) {
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);
update(node*2 + 1, mid + 1, end, l, r, val);
tree[node] = Math.min(tree[node*2], tree[node*2+1]);
}
function query(node, start, end, l, r) {
if (start > end || start > r || end < l) return MAX;
if (lazy[node] !== 0) {
tree[node] += lazy[node];
if (start !== end) {
lazy[node*2] += lazy[node];
lazy[node*2+1] += lazy[node];
}
lazy[node] = 0;
}
if (start >= l && end <= r)
return tree[node];
let mid = Math.floor((start + end) / 2);
let p1 = query(node*2, start, mid, l, r);
let p2 = query(node*2 + 1, mid + 1, end, l, r);
return Math.min(p1, p2);
}
function main() {
let n = 5;
build(1, 0, n-1);
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);
} else if (type === 2) {
let l = q[1], r = q[2];
let ans = query(1, 0, n-1, l, r-1);
console.log(ans);
}
}
}
main();
|
Python3
MAX = int ( 1e5 )
tree = [ 0 ] * ( 4 * MAX )
lazy = [ 0 ] * ( 4 * MAX )
def build(node, start, end):
if start = = end:
tree[node] = 0
else :
mid = (start + end) / / 2
build( 2 * node, start, mid)
build( 2 * node + 1 , mid + 1 , end)
tree[node] = min (tree[ 2 * node], tree[ 2 * node + 1 ])
def update(node, start, end, l, r, val):
if lazy[node] ! = 0 :
tree[node] + = lazy[node]
if start ! = end:
lazy[node * 2 ] + = lazy[node]
lazy[node * 2 + 1 ] + = lazy[node]
lazy[node] = 0
if start > end or start > r or end < l:
return
if start > = l and end < = r:
tree[node] + = val
if start ! = end:
lazy[node * 2 ] + = val
lazy[node * 2 + 1 ] + = val
return
mid = (start + end) / / 2
update(node * 2 , start, mid, l, r, val)
update(node * 2 + 1 , mid + 1 , end, l, r, val)
tree[node] = min (tree[node * 2 ], tree[node * 2 + 1 ])
def query(node, start, end, l, r):
if start > end or start > r or end < l:
return MAX
if lazy[node] ! = 0 :
tree[node] + = lazy[node]
if start ! = end:
lazy[node * 2 ] + = lazy[node]
lazy[node * 2 + 1 ] + = lazy[node]
lazy[node] = 0
if start > = l and end < = r:
return tree[node]
mid = (start + end) / / 2
p1 = query(node * 2 , start, mid, l, r)
p2 = query(node * 2 + 1 , mid + 1 , end, l, r)
return min (p1, p2)
def main():
n = 5
build( 1 , 0 , n - 1 )
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)
elif type = = 2 :
l, r = q[ 1 ], q[ 2 ]
ans = query( 1 , 0 , n - 1 , l, r - 1 )
print (ans)
main()
|
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.
|