There is an array of n elements, initially filled with zeros. The task is to perform q queries from given queries[][] and there are two types of queries:
- Type 1 (i.e queries[i][0] == 1): Assign value val = queries[i][3] to all elements on the segment l = queries[i][1] to r = queries[i][2].
- Type 2 (i.e queries[i][0] == 2): Find the minimum on the segment from l = queries[i][1] to r = queries[i][2].
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 4 4 0
Approach: To solve the problem follow the below Idea.
The idea is to use a Segment Tree Data Structure, a binary tree data structure where each node represents an interval or segment of the array. The root of the tree represents the entire array, and each leaf node represents a single element of the array. This structure allows us to perform operations on a range of elements in logarithmic time.
- Build: The segment tree is built such that each node stores the minimum value in its corresponding segment of the array.
- Update: When we need to update a range of elements (query type 1), we use a technique called lazy propagation. Instead of immediately updating all the elements in the range, we mark the corresponding node in the segment tree as “lazy”. This means that the update is pending, and should be applied later when we actually need to access the elements in that range.
- Push: Before we perform an operation on a node (either an update or a query), we first “push” the pending updates to its children. This ensures that our operation is performed on up-to-date data.
- Query: To find the minimum value in a range (query type 2), we traverse the segment tree from the root to the leaves, pushing any pending updates along the way. We combine the results from the relevant nodes to obtain the minimum value in the desired range.
Steps were taken to implement the approach:
- Create the array a of size n+1, the segment tree t of size 4*n, and the lazy propagation array lazy of size 4*n.
- Call the build function to construct the initial segment tree. Initialize each node with zero.
- Process Operations: Loop over each operation from 1 to m.
- For each operation:
- If it is of type 1 (update operation):
- Read the left boundary l, right boundary r, and the value to be assigned val.
- Call the update function to update the range [l, r-1] with the value val.
- If it is of type 2 (query operation):
- Read the left boundary l and right boundary r.
- Call the query function to find the minimum value in the range [l, r-1].
- Print the result of the query.
Below is the Implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
int n, q, t[MAXN << 2], lazy[MAXN << 2];
void build( int v, int tl, int tr)
{
if (tl == tr) {
t[v] = 0;
}
else {
int tm = (tl + tr) / 2;
build(v * 2, tl, tm );
build(v * 2 + 1, tm + 1, tr);
t[v] = min(t[v * 2], t[v * 2 + 1]);
}
}
void push( int v)
{
t[v * 2] = t[v * 2 + 1] = lazy[v];
lazy[v * 2] = lazy[v * 2 + 1] = lazy[v];
lazy[v] = 0;
}
void update( int v, int tl, int tr, int l, int r, int val)
{
if (lazy[v])
push(v);
if (l > r)
return ;
if (l == tl && r == tr) {
t[v] = val;
lazy[v] = val;
}
else {
int tm = (tl + tr) / 2;
update(v * 2, tl, tm , l, min(r, tm ), val);
update(v * 2 + 1, tm + 1, tr, max(l, tm + 1), r,
val);
t[v] = min(t[v * 2], t[v * 2 + 1]);
}
}
int query( int v, int tl, int tr, int l, int r)
{
if (lazy[v])
push(v);
if (l > r)
return INT_MAX;
if (l <= tl && tr <= r) {
return t[v];
}
int tm = (tl + tr) / 2;
return min(
query(v * 2, tl, tm , l, min(r, tm )),
query(v * 2 + 1, tm + 1, tr, max(l, tm + 1), r));
}
int main()
{
n = 5;
q = 6;
vector<vector< int > > queries
= { { 1, 0, 3, 3 }, { 2, 1, 2 }, { 1, 1, 4, 4 },
{ 2, 1, 3 }, { 2, 1, 4 }, { 2, 3, 5 } };
build(1, 0, n - 1);
for ( int i = 0; i < q; i++) {
int type = queries[i][0];
if (type == 1) {
int l = queries[i][1];
int r = queries[i][2];
int val = queries[i][3];
update(1, 0, n - 1, l, r - 1, val);
}
else {
int l = queries[i][1];
int r = queries[i][2];
cout << query(1, 0, n - 1, l, r - 1) << "\n" ;
}
}
return 0;
}
|
Java
import java.util.*;
public class SegmentTreeLazyPropagation {
static final int MAXN = 100005 ;
static int n, q, t[] = new int [MAXN << 2 ], lazy[] = new int [MAXN << 2 ];
static void build( int v, int tl, int tr) {
if (tl == tr) {
t[v] = 0 ;
} else {
int tm = (tl + tr) / 2 ;
build(v * 2 , tl, tm);
build(v * 2 + 1 , tm + 1 , tr);
t[v] = Math.min(t[v * 2 ], t[v * 2 + 1 ]);
}
}
static void push( int v) {
t[v * 2 ] = t[v * 2 + 1 ] = lazy[v];
lazy[v * 2 ] = lazy[v * 2 + 1 ] = lazy[v];
lazy[v] = 0 ;
}
static void update( int v, int tl, int tr, int l, int r, int val) {
if (lazy[v] != 0 )
push(v);
if (l > r)
return ;
if (l == tl && r == tr) {
t[v] = val;
lazy[v] = val;
} else {
int tm = (tl + tr) / 2 ;
update(v * 2 , tl, tm, l, Math.min(r, tm), val);
update(v * 2 + 1 , tm + 1 , tr, Math.max(l, tm + 1 ), r, val);
t[v] = Math.min(t[v * 2 ], t[v * 2 + 1 ]);
}
}
static int query( int v, int tl, int tr, int l, int r) {
if (lazy[v] != 0 )
push(v);
if (l > r)
return Integer.MAX_VALUE;
if (l <= tl && tr <= r) {
return t[v];
}
int tm = (tl + tr) / 2 ;
return Math.min(query(v * 2 , tl, tm, l, Math.min(r, tm)),
query(v * 2 + 1 , tm + 1 , tr, Math.max(l, tm + 1 ), r));
}
public static void main(String[] args) {
n = 5 ;
q = 6 ;
int [][] queries = { { 1 , 0 , 3 , 3 }, { 2 , 1 , 2 }, { 1 , 1 , 4 , 4 },
{ 2 , 1 , 3 }, { 2 , 1 , 4 }, { 2 , 3 , 5 } };
build( 1 , 0 , n - 1 );
for ( int i = 0 ; i < q; i++) {
int type = queries[i][ 0 ];
if (type == 1 ) {
int l = queries[i][ 1 ];
int r = queries[i][ 2 ];
int val = queries[i][ 3 ];
update( 1 , 0 , n - 1 , l, r - 1 , val);
}
else {
int l = queries[i][ 1 ];
int r = queries[i][ 2 ];
System.out.println(query( 1 , 0 , n - 1 , l, r - 1 ));
}
}
}
}
|
Python3
MAXN = 100005
n, q = 0 , 0
t = [ 0 ] * ( 4 * MAXN)
lazy = [ 0 ] * ( 4 * MAXN)
def build(v, tl, tr):
if tl = = tr:
t[v] = 0
else :
tm = (tl + tr) / / 2
build(v * 2 , tl, tm)
build(v * 2 + 1 , tm + 1 , tr)
t[v] = min (t[v * 2 ], t[v * 2 + 1 ])
def push(v):
t[v * 2 ] = t[v * 2 + 1 ] = lazy[v]
lazy[v * 2 ] = lazy[v * 2 + 1 ] = lazy[v]
lazy[v] = 0
def update(v, tl, tr, l, r, val):
if lazy[v]:
push(v)
if l > r:
return
if l = = tl and r = = tr:
t[v] = val
lazy[v] = val
else :
tm = (tl + tr) / / 2
update(v * 2 , tl, tm, l, min (r, tm), val)
update(v * 2 + 1 , tm + 1 , tr, max (l, tm + 1 ), r, val)
t[v] = min (t[v * 2 ], t[v * 2 + 1 ])
def query(v, tl, tr, l, r):
if lazy[v]:
push(v)
if l > r:
return float ( 'inf' )
if l < = tl and tr < = r:
return t[v]
tm = (tl + tr) / / 2
return min (query(v * 2 , tl, tm, l, min (r, tm)), query(v * 2 + 1 , tm + 1 , tr, max (l, tm + 1 ), r))
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 ]
]
build( 1 , 0 , n - 1 )
for i in range (q):
type = queries[i][ 0 ]
if type = = 1 :
l = queries[i][ 1 ]
r = queries[i][ 2 ]
val = queries[i][ 3 ]
update( 1 , 0 , n - 1 , l, r - 1 , val)
else :
l = queries[i][ 1 ]
r = queries[i][ 2 ]
print (query( 1 , 0 , n - 1 , l, r - 1 ))
|
C#
using System;
using System.Collections.Generic;
public class GFG
{
const int MAXN = 100005;
static int n, q;
static int [] t = new int [MAXN << 2];
static int [] lazy = new int [MAXN << 2];
static void Build( int v, int tl, int tr)
{
if (tl == tr)
{
t[v] = 0;
}
else
{
int tm = (tl + tr) / 2;
Build(v * 2, tl, tm);
Build(v * 2 + 1, tm + 1, tr);
t[v] = Math.Min(t[v * 2], t[v * 2 + 1]);
}
}
static void Push( int v)
{
t[v * 2] = t[v * 2 + 1] = lazy[v];
lazy[v * 2] = lazy[v * 2 + 1] = lazy[v];
lazy[v] = 0;
}
static void Update( int v, int tl, int tr, int l, int r, int val)
{
if (lazy[v] != 0)
Push(v);
if (l > r)
return ;
if (l == tl && r == tr)
{
t[v] = val;
lazy[v] = val;
}
else
{
int tm = (tl + tr) / 2;
Update(v * 2, tl, tm, l, Math.Min(r, tm), val);
Update(v * 2 + 1, tm + 1, tr, Math.Max(l, tm + 1), r, val);
t[v] = Math.Min(t[v * 2], t[v * 2 + 1]);
}
}
static int Query( int v, int tl, int tr, int l, int r)
{
if (lazy[v] != 0)
Push(v);
if (l > r)
return int .MaxValue;
if (l <= tl && tr <= r)
{
return t[v];
}
int tm = (tl + tr) / 2;
return Math.Min(
Query(v * 2, tl, tm, l, Math.Min(r, tm)),
Query(v * 2 + 1, tm + 1, tr, Math.Max(l, tm + 1), r));
}
public static void Main()
{
n = 5;
q = 6;
List<List< int >> queries = new List<List< int >>
{
new List< int > {1, 0, 3, 3},
new List< int > {2, 1, 2},
new List< int > {1, 1, 4, 4},
new List< int > {2, 1, 3},
new List< int > {2, 1, 4},
new List< int > {2, 3, 5}
};
Build(1, 0, n - 1);
for ( int i = 0; i < q; i++)
{
int type = queries[i][0];
if (type == 1)
{
int l = queries[i][1];
int r = queries[i][2];
int val = queries[i][3];
Update(1, 0, n - 1, l, r - 1, val);
}
else
{
int l = queries[i][1];
int r = queries[i][2];
Console.WriteLine(Query(1, 0, n - 1, l, r - 1));
}
}
}
}
|
Javascript
const MAXN = 100005;
let n = 0;
let q = 0;
let t = new Array(4 * MAXN).fill(0);
let lazy = new Array(4 * MAXN).fill(0);
function build(v, tl, tr) {
if (tl === tr) {
t[v] = 0;
} else {
const tm = Math.floor((tl + tr) / 2);
build(v * 2, tl, tm);
build(v * 2 + 1, tm + 1, tr);
t[v] = Math.min(t[v * 2], t[v * 2 + 1]);
}
}
function push(v) {
t[v * 2] = t[v * 2 + 1] = lazy[v];
lazy[v * 2] = lazy[v * 2 + 1] = lazy[v];
lazy[v] = 0;
}
function update(v, tl, tr, l, r, val) {
if (lazy[v]) {
push(v);
}
if (l > r) {
return ;
}
if (l === tl && r === tr) {
t[v] = val;
lazy[v] = val;
} else {
const tm = Math.floor((tl + tr) / 2);
update(v * 2, tl, tm, l, Math.min(r, tm), val);
update(v * 2 + 1, tm + 1, tr, Math.max(l, tm + 1), r, val);
t[v] = Math.min(t[v * 2], t[v * 2 + 1]);
}
}
function query(v, tl, tr, l, r) {
if (lazy[v]) {
push(v);
}
if (l > r) {
return Infinity;
}
if (l <= tl && tr <= r) {
return t[v];
}
const tm = Math.floor((tl + tr) / 2);
return Math.min(
query(v * 2, tl, tm, l, Math.min(r, tm)),
query(v * 2 + 1, tm + 1, tr, Math.max(l, tm + 1), r)
);
}
n = 5;
q = 6;
const queries = [
[1, 0, 3, 3],
[2, 1, 2],
[1, 1, 4, 4],
[2, 1, 3],
[2, 1, 4],
[2, 3, 5]
];
build(1, 0, n - 1);
for (let i = 0; i < q; i++) {
const type = queries[i][0];
if (type === 1) {
const l = queries[i][1];
const r = queries[i][2];
const val = queries[i][3];
update(1, 0, n - 1, l, r - 1, val);
} else {
const l = queries[i][1];
const r = queries[i][2];
console.log(query(1, 0, n - 1, l, r - 1));
}
}
|
Time Complexity:
- Build Function: O(n)
- Update Function: O(log n)
- Query Function: O(log n)
- Overall: O(n + m log n)
Auxiliary Space: O(n) for segment
|