给定数组arr [0。 。 。 n-1]。查找从索引l到r的元素的最大值,其中0 <= l <= r <= n-1。另外,将数组指定元素的值更改为新值x。我们需要做arr [i] = x,其中0 <= i <= n-1,然后用更新的值找到给定范围的最大元素。
例子 :
Input : {1, 3, 5, 7, 9, 11}
Maximum Query : L = 1, R = 3
update : set arr[1] = 8
Output :
Max of values in given range = 7
Updated max of values in given range = 8
一个简单的解决方案是运行从l到r的循环,并计算给定范围内的元素最大值。要更新值,只需做arr [i] = x。第一次操作花费O(n)时间,第二次操作花费O(1)时间。
高效的方法:在这里,我们需要在O(Logn)时间执行操作,因此我们可以使用Segment Tree在O(Logn)时间执行这两项操作。
段树的表示
1.叶节点是输入数组的元素。
2.每个内部节点代表其所有子节点的最大值。
树的数组表示形式用于表示段树。对于索引i处的每个节点,左子节点在索引2 * i + 1处,右子节点在索引2 * i + 2处,父节点在索引(i-1)/ 2处。
从给定数组构造细分树:
我们从一个段arr [0开始。 。 。 [n-1],并且每次我们将当前段分成两半(如果尚未变成长度为1的段),然后在这两个半段上调用相同的过程,则对于每个这样的段,我们都会存储最大值段树节点中的值。除最后一个级别外,已构建的段树的所有级别都将被完全填充。而且,该树将是完整的二叉树,因为我们总是在每个级别将分段分为两半。由于构造的树始终是具有n个叶子的完整二叉树,因此将有n-1个内部节点。因此,总节点数将为2 * n – 1 。段树的高度将为log2n 。由于树是使用数组表示的,因此必须保持父索引和子索引之间的关系,因此分配给段树的内存大小将为2 *(2 ^ ceil(log2n))– 1 。
查询给定范围的最大值:构造树后,下面是查找给定范围最大值的算法。
node--> node number, l -->
query start index, r --> query end index;
int getMax(node, l, r)
{
if range of node is within l and r
return value of node
else if range of node is completely outside l and r
return -1
else
return max(getMax(node's left child, l, r),
getMax(node's right child, l, r))
}
下面是上述方法的实现:
C++
// CPP code for range maximum query and updates
#include
using namespace std;
// A utility function to get the
// middle index of given range.
int getMid(int s, int e)
{
return s + (e - s) / 2;
}
/* A recursive function to get the sum of
values in given range of the array.
The following are parameters for this
function.
st -> Pointer to segment tree
node -> Index of current node in
the segment tree .
ss & se -> Starting and ending indexes
of the segment represented
by current node, i.e., st[node]
l & r -> Starting and ending indexes
of range query */
int MaxUtil(int* st, int ss, int se, int l,
int r, int node)
{
// If segment of this node is completely
// part of given range, then return
// the max of segment
if (l <= ss && r >= se)
return st[node];
// If segment of this node does not
// belong to given range
if (se < l || ss > r)
return -1;
// If segment of this node is partially
// the part of given range
int mid = getMid(ss, se);
return max(MaxUtil(st, ss, mid, l, r,
2 * node + 1),
MaxUtil(st, mid + 1, se, l,
r, 2 * node + 2));
}
/* A recursive function to update the nodes
which have the given index in their range.
The following are parameters st, ss and
se are same as defined
above index -> index of the element
to be updated.*/
void updateValue(int arr[], int* st, int ss, int se,
int index, int value, int node)
{
if (index < ss || index > se)
{
cout << "Invalid Input" << endl;
return;
}
if (ss == se)
{
// update value in array and in segment tree
arr[index] = value;
st[node] = value;
}
else {
int mid = getMid(ss, se);
if (index >= ss && index <= mid)
updateValue(arr, st,
ss, mid, index,
value, 2 * node + 1);
else
updateValue(arr,
st, mid + 1, se,
index,
value, 2 * node + 2);
st[node] = max(st[2 * node + 1],
st[2 * node + 2]);
}
return;
}
// Return max of elements in range from
// index l (query start) to r (query end).
int getMax(int* st, int n, int l, int r)
{
// Check for erroneous input values
if (l < 0 || r > n - 1 || l > r)
{
printf("Invalid Input");
return -1;
}
return MaxUtil(st, 0, n - 1, l, r, 0);
}
// A recursive function that constructs Segment
// Tree for array[ss..se]. si is index of
// current node in segment tree st
int constructSTUtil(int arr[], int ss, int se,
int* st, int si)
{
// If there is one element in array, store
// it in current node of
// segment tree and return
if (ss == se)
{
st[si] = arr[ss];
return arr[ss];
}
// If there are more than one elements, then
// recur for left and right subtrees and
// store the max of values in this node
int mid = getMid(ss, se);
st[si] = max(constructSTUtil(arr, ss, mid, st,
si * 2 + 1),
constructSTUtil(arr, mid + 1, se,
st, si * 2 + 2));
return st[si];
}
/* Function to construct segment tree
from given array.
This function allocates memory for
segment tree.*/
int* constructST(int arr[], int n)
{
// Height of segment tree
int x = (int)(ceil(log2(n)));
// Maximum size of segment tree
int max_size = 2 * (int)pow(2, x) - 1;
// Allocate memory
int* st = new int[max_size];
// Fill the allocated memory st
constructSTUtil(arr, 0, n - 1, st, 0);
// Return the constructed segment tree
return st;
}
// Driver code
int main()
{
int arr[] = { 1, 3, 5, 7, 9, 11 };
int n = sizeof(arr) / sizeof(arr[0]);
// Build segment tree from given array
int* st = constructST(arr, n);
// Print max of values in array
// from index 1 to 3
cout << "Max of values in given range = "
<< getMax(st, n, 1, 3) << endl;
// Update: set arr[1] = 8 and update
// corresponding segment tree nodes.
updateValue(arr, st, 0, n - 1, 1, 8, 0);
// Find max after the value is updated
cout << "Updated max of values in given range = "
<< getMax(st, n, 1, 3) << endl;
return 0;
}
Java
// Java code for range maximum query and updates
import java.io.*;
import java.util.*;
class GFG {
// A utility function to get the
// middle index of given range.
static int getMid(int s, int e)
{
return s + (e - s) / 2;
}
/*
* A recursive function to get the sum
of values in given range of the array.
* The following are parameters
for this function.
*
* st -> Pointer to segment tree
* node -> Index of current node in
* the segment tree.
* ss & se -> Starting and ending indexes
* of the segment represented
* by current node, i.e., st[node]
* l & r -> Starting and ending indexes
* of range query
*/
static int MaxUtil(int[] st, int ss,
int se, int l,
int r, int node)
{
// If segment of this node is completely
// part of given range, then return
// the max of segment
if (l <= ss && r >= se)
return st[node];
// If segment of this node does not
// belong to given range
if (se < l || ss > r)
return -1;
// If segment of this node is partially
// the part of given range
int mid = getMid(ss, se);
return Math.max(
MaxUtil(st, ss, mid, l, r,
2 * node + 1),
MaxUtil(st, mid + 1, se, l, r,
2 * node + 2));
}
/*
* A recursive function to update the
nodes which have the given index in their
* range. The following are parameters
st, ss and se are same as defined above
* index -> index of the element to be updated.
*/
static void updateValue(int arr[], int[]
st, int ss,
int se, int index,
int value,
int node)
{
if (index < ss || index > se) {
System.out.println("Invalid Input");
return;
}
if (ss == se) {
// update value in array and in
// segment tree
arr[index] = value;
st[node] = value;
}
else {
int mid = getMid(ss, se);
if (index >= ss && index <= mid)
updateValue(arr, st, ss, mid,
index, value,
2 * node + 1);
else
updateValue(arr, st, mid + 1, se, index,
value, 2 * node + 2);
st[node] = Math.max(st[2 * node + 1],
st[2 * node + 2]);
}
return;
}
// Return max of elements in range from
// index l (query start) to r (query end).
static int getMax(int[] st, int n, int l, int r)
{
// Check for erroneous input values
if (l < 0 || r > n - 1 || l > r) {
System.out.printf("Invalid Input\n");
return -1;
}
return MaxUtil(st, 0, n - 1, l, r, 0);
}
// A recursive function that constructs Segment
// Tree for array[ss..se]. si is index of
// current node in segment tree st
static int constructSTUtil(int arr[],
int ss, int se,
int[] st, int si)
{
// If there is one element in array, store
// it in current node of segment tree and return
if (ss == se) {
st[si] = arr[ss];
return arr[ss];
}
// If there are more than one elements, then
// recur for left and right subtrees and
// store the max of values in this node
int mid = getMid(ss, se);
st[si] = Math.max(
constructSTUtil(arr, ss, mid,
st, si * 2 + 1),
constructSTUtil(arr, mid + 1,
se, st,
si * 2 + 2));
return st[si];
}
/*
* Function to construct segment tree from
given array. This function allocates
* memory for segment tree.
*/
static int[] constructST(int arr[], int n)
{
// Height of segment tree
int x = (int)Math.ceil(Math.log(n) / Math.log(2));
// Maximum size of segment tree
int max_size = 2 * (int)Math.pow(2, x) - 1;
// Allocate memory
int[] st = new int[max_size];
// Fill the allocated memory st
constructSTUtil(arr, 0, n - 1, st, 0);
// Return the constructed segment tree
return st;
}
// Driver Code
public static void main(String[] args)
{
int[] arr = { 1, 3, 5, 7, 9, 11 };
int n = arr.length;
// Build segment tree from given array
int[] st = constructST(arr, n);
// Print max of values in array
// from index 1 to 3
System.out.println("Max of values in given range = "
+ getMax(st, n, 1, 3));
// Update: set arr[1] = 8 and update
// corresponding segment tree nodes.
updateValue(arr, st, 0, n - 1, 1, 8, 0);
// Find max after the value is updated
System.out.println(
"Updated max of values in given range = "
+ getMax(st, n, 1, 3));
}
}
// This code is contributed by
// sanjeev2552
Python3
# Python3 code for range maximum query and updates
from math import ceil, log
# A utility function to get the
# middle index of given range.
def getMid(s, e):
return s + (e - s) // 2
# /* A recursive function to get the sum of
# values in given range of the array.
# The following are parameters for this
# function.
#
# st -> Pointer to segment tree
# node -> Index of current node in
# the segment tree .
# ss & se -> Starting and ending indexes
# of the segment represented
# by current node, i.e., st[node]
# l & r -> Starting and ending indexes
# of range query */
def MaxUtil(st, ss, se, l, r, node):
# If segment of this node is completely
# part of given range, then return
# the max of segment
if (l <= ss and r >= se):
return st[node]
# If segment of this node does not
# belong to given range
if (se < l or ss > r):
return -1
# If segment of this node is partially
# the part of given range
mid = getMid(ss, se)
return max(MaxUtil(st, ss, mid, l, r,
2 * node + 1),
MaxUtil(st, mid + 1, se, l,
r, 2 * node + 2))
#
# /* A recursive function to update the nodes which
# have the given index in their range. The following
# are parameters st, ss and se are same as defined
# above index -> index of the element to be updated.*/
def updateValue(arr, st, ss, se, index, value, node):
if (index < ss or index > se):
print("Invalid Input")
return
if (ss == se):
# update value in array and in segment tree
arr[index] = value
st[node] = value
else:
mid = getMid(ss, se)
if (index >= ss and index <= mid):
updateValue(arr, st, ss, mid, index,
value, 2 * node + 1)
else:
updateValue(arr, st, mid + 1, se,
index, value, 2 * node + 2)
st[node] = max(st[2 * node + 1],
st[2 * node + 2])
return
# Return max of elements in range from
# index l (query start) to r (query end).
def getMax(st, n, l, r):
# Check for erroneous input values
if (l < 0 or r > n - 1 or l > r):
printf("Invalid Input")
return -1
return MaxUtil(st, 0, n - 1, l, r, 0)
# A recursive function that constructs Segment
# Tree for array[ss..se]. si is index of
# current node in segment tree st
def constructSTUtil(arr, ss, se, st, si):
# If there is one element in array, store
# it in current node of segment tree and return
if (ss == se):
st[si] = arr[ss]
return arr[ss]
# If there are more than one elements, then
# recur for left and right subtrees and
# store the max of values in this node
mid = getMid(ss, se)
st[si] = max(constructSTUtil(arr, ss, mid, st,
si * 2 + 1),
constructSTUtil(arr, mid + 1, se,
st, si * 2 + 2))
return st[si]
#
# /* Function to construct segment tree from given array.
# This function allocates memory for segment tree.*/
def constructST(arr, n):
# Height of segment tree
x = ceil(log(n, 2))
# Maximum size of segment tree
max_size = 2 * pow(2, x) - 1
# Allocate memory
st = [0]*max_size
# Fill the allocated memory st
constructSTUtil(arr, 0, n - 1, st, 0)
# Return the constructed segment tree
return st
# Driver code
if __name__ == '__main__':
arr = [1, 3, 5, 7, 9, 11]
n = len(arr)
# Build segment tree from given array
st = constructST(arr, n)
# Prmax of values in array
# from index 1 to 3
print("Max of values= ", getMax(st, n, 1, 3))
# Update: set arr[1] = 8 and update
# corresponding segment tree nodes.
updateValue(arr, st, 0, n - 1, 1, 8, 0)
# Find max after the value is updated
print("Updated values = ", getMax(st, n, 1, 3))
# This code is contributed by mohit kumar 29
C#
// C# code for range maximum query and updates
using System;
class GFG
{
// A utility function to get the
// middle index of given range.
static int getMid(int s, int e)
{
return s + (e - s) / 2;
}
/*
* A recursive function to get the sum
of values in given range of the array.
* The following are parameters
for this function.
*
* st -> Pointer to segment tree
* node -> Index of current node in
* the segment tree.
* ss & se -> Starting and ending indexes
* of the segment represented
* by current node, i.e., st[node]
* l & r -> Starting and ending indexes
* of range query
*/
static int MaxUtil(int[] st, int ss, int se,
int l, int r, int node)
{
// If segment of this node is completely
// part of given range, then return
// the max of segment
if (l <= ss && r >= se)
{
return st[node];
}
// If segment of this node does not
// belong to given range
if (se < l || ss > r)
{
return -1;
}
// If segment of this node is partially
// the part of given range
int mid = getMid(ss, se);
return Math.Max(MaxUtil(st, ss, mid, l, r, 2 * node + 1),
MaxUtil(st, mid + 1, se, l, r,2 * node + 2));
}
/*
* A recursive function to update the
nodes which have the given index in their
* range. The following are parameters
st, ss and se are same as defined above
* index -> index of the element to be updated.
*/
static void updateValue(int[] arr,int[] st, int ss,
int se, int index,
int value,int node)
{
if (index < ss || index > se)
{
Console.WriteLine("Invalid Input");
return ;
}
if (ss == se)
{
// update value in array and in
// segment tree
arr[index] = value;
st[node] = value;
}
else
{
int mid = getMid(ss, se);
if (index >= ss && index <= mid)
{
updateValue(arr, st, ss, mid, index,
value, 2 * node + 1);
}
else
{
updateValue(arr, st, mid + 1, se,
index,value, 2 * node + 2);
}
st[node] = Math.Max(st[2 * node + 1],
st[2 * node + 2]);
}
return;
}
// Return max of elements in range from
// index l (query start) to r (query end).
static int getMax(int[] st, int n, int l, int r)
{
// Check for erroneous input values
if(l < 0 || r > n - 1 || l > r)
{
Console.WriteLine("Invalid Input");
return -1;
}
return MaxUtil(st, 0, n - 1, l, r, 0);
}
// A recursive function that constructs Segment
// Tree for array[ss..se]. si is index of
// current node in segment tree st
static int constructSTUtil(int[] arr,int ss,
int se,int[] st, int si)
{
// If there is one element in array, store
// it in current node of segment tree and return
if(ss == se)
{
st[si] = arr[ss];
return arr[ss];
}
// If there are more than one elements, then
// recur for left and right subtrees and
// store the max of values in this node
int mid = getMid(ss, se);
st[si] = Math.Max(constructSTUtil(arr, ss, mid,st, si * 2 + 1),
constructSTUtil(arr, mid + 1,se, st,si * 2 + 2));
return st[si];
}
/*
* Function to construct segment tree from
given array. This function allocates
* memory for segment tree.
*/
static int[] constructST(int[] arr, int n)
{
// Height of segment tree
int x = (int)Math.Ceiling(Math.Log(n) / Math.Log(2));
// Maximum size of segment tree
int max_size = 2 * (int)Math.Pow(2, x) - 1;
// Allocate memory
int[] st = new int[max_size];
// Fill the allocated memory st
constructSTUtil(arr, 0, n - 1, st, 0);
// Return the constructed segment tree
return st;
}
// Driver Code
static public void Main ()
{
int[] arr = { 1, 3, 5, 7, 9, 11 };
int n = arr.Length;
// Build segment tree from given array
int[] st = constructST(arr, n);
// Print max of values in array
// from index 1 to 3
Console.WriteLine("Max of values in given range = "
+ getMax(st, n, 1, 3));
// Update: set arr[1] = 8 and update
// corresponding segment tree nodes.
updateValue(arr, st, 0, n - 1, 1, 8, 0);
// Find max after the value is updated
Console.WriteLine("Updated max of values in given range = "
+ getMax(st, n, 1, 3));
}
}
// This code is contributed by avanitrachhadiya2155
Max of values in given range = 7
Updated max of values in given range = 8