给定大小为N的数组arr [] 。有两种类型的操作:
- Update(l,r,x):将a [i](l <= i <= r)递增x。
- Query(l,r):在数组l到r(包括两者)中找到数组中的最大值。
例子:
Input: arr[] = {1, 2, 3, 4, 5}
Update(0, 3, 4)
Query(1, 4)
Output: 8
After applying the update operation
in the given range with given value array becomes {5, 6, 7, 8, 5}.
Then the maximum value in the range 1 to 4 is 8.
Input: arr[] = {1, 2, 3, 4, 5}
Update(0, 0, 10)
Query(0, 4)
Output: 11
方法:前面已经解释了有关分段树中的惰性传播的详细说明。问题中唯一需要更改的是在调用父节点查询时在两个子节点之间返回最大值。请参阅代码以获得更好的理解。
下面是上述方法的实现:
C++
// C++ implementation of the approach
#include
using namespace std;
#define MAX 1000
// Ideally, we should not use global variables and large
// constant-sized arrays, we have done it here for simplicity
// To store segment tree
int tree[MAX] = { 0 };
// To store pending updates
int lazy[MAX] = { 0 };
// si -> index of current node in segment tree
// ss and se -> Starting and ending indexes of
// elements for which current nodes stores sum
// us and ue -> starting and ending indexes of update query
// diff -> which we need to add in the range us to ue
void updateRangeUtil(int si, int ss, int se, int us,
int ue, int diff)
{
// If lazy value is non-zero for current node of segment
// tree, then there are some pending updates. So we need
// to make sure that the pending updates are done before
// making new updates. Because this value may be used by
// parent after recursive calls (See last line of this
// function)
if (lazy[si] != 0) {
// Make pending updates using value stored in lazy
// nodes
tree[si] += lazy[si];
// Checking if it is not leaf node because if
// it is leaf node then we cannot go further
if (ss != se) {
// We can postpone updating children we don't
// need their new values now.
// Since we are not yet updating children of si,
// we need to set lazy flags for the children
lazy[si * 2 + 1] += lazy[si];
lazy[si * 2 + 2] += lazy[si];
}
// Set the lazy value for current node as 0 as it
// has been updated
lazy[si] = 0;
}
// Out of range
if (ss > se || ss > ue || se < us)
return;
// Current segment is fully in range
if (ss >= us && se <= ue) {
// Add the difference to current node
tree[si] += diff;
// Same logic for checking leaf node or not
if (ss != se) {
// This is where we store values in lazy nodes,
// rather than updating the segment tree itelf
// Since we don't need these updated values now
// we postpone updates by storing values in lazy[]
lazy[si * 2 + 1] += diff;
lazy[si * 2 + 2] += diff;
}
return;
}
// If not completely in range, but overlaps
// recur for children
int mid = (ss + se) / 2;
updateRangeUtil(si * 2 + 1, ss, mid, us, ue, diff);
updateRangeUtil(si * 2 + 2, mid + 1, se, us, ue, diff);
// And use the result of children calls
// to update this node
tree[si] = max(tree[si * 2 + 1], tree[si * 2 + 2]);
}
// Function to update a range of values in segment
// tree
// us and eu -> starting and ending indexes of update query
// ue -> ending index of update query
// diff -> which we need to add in the range us to ue
void updateRange(int n, int us, int ue, int diff)
{
updateRangeUtil(0, 0, n - 1, us, ue, diff);
}
// A recursive function to get the sum of values in given
// a range of the array. The following are the parameters
// for this function
// si --> Index of the current node in the segment tree
// Initially, 0 is passed as root is always at index 0
// ss & se --> Starting and ending indexes of the
// segment represented by current node
// i.e., tree[si]
// qs & qe --> Starting and ending indexes of query
// range
int getSumUtil(int ss, int se, int qs, int qe, int si)
{
// If lazy flag is set for current node of segment tree
// then there are some pending updates. So we need to
// make sure that the pending updates are done before
// processing the sub sum query
if (lazy[si] != 0) {
// Make pending updates to this node. Note that this
// node represents sum of elements in arr[ss..se] and
// all these elements must be increased by lazy[si]
tree[si] += lazy[si];
// Checking if it is not leaf node because if
// it is leaf node then we cannot go further
if (ss != se) {
// Since we are not yet updating children os si,
// we need to set lazy values for the children
lazy[si * 2 + 1] += lazy[si];
lazy[si * 2 + 2] += lazy[si];
}
// Unset the lazy value for current node as it has
// been updated
lazy[si] = 0;
}
// Out of range
if (ss > se || ss > qe || se < qs)
return 0;
// At this point, we are sure that pending lazy updates
// are done for current node. So we can return value
// (same as it was for a query in our previous post)
// If this segment lies in range
if (ss >= qs && se <= qe)
return tree[si];
// If a part of this segment overlaps with the given
// range
int mid = (ss + se) / 2;
return max(getSumUtil(ss, mid, qs, qe, 2 * si + 1),
getSumUtil(mid + 1, se, qs, qe, 2 * si + 2));
}
// Return sum of elements in range from index qs (query
// start) to qe (query end). It mainly uses getSumUtil()
int getSum(int n, int qs, int qe)
{
// Check for erroneous input values
if (qs < 0 || qe > n - 1 || qs > qe) {
printf("Invalid Input");
return -1;
}
return getSumUtil(0, n - 1, qs, qe, 0);
}
// A recursive function that constructs Segment Tree for
// array[ss..se]. si is index of current node in segment
// tree st.
void constructSTUtil(int arr[], int ss, int se, int si)
{
// out of range as ss can never be greater than se
if (ss > se)
return;
// If there is one element in array, store it in
// current node of segment tree and return
if (ss == se) {
tree[si] = arr[ss];
return;
}
// If there are more than one elements, then recur
// for left and right subtrees and store the sum
// of values in this node
int mid = (ss + se) / 2;
constructSTUtil(arr, ss, mid, si * 2 + 1);
constructSTUtil(arr, mid + 1, se, si * 2 + 2);
tree[si] = max(tree[si * 2 + 1], tree[si * 2 + 2]);
}
// Function to construct a segment tree from a given array
// This function allocates memory for segment tree and
// calls constructSTUtil() to fill the allocated memory
void constructST(int arr[], int n)
{
// Fill the allocated memory st
constructSTUtil(arr, 0, n - 1, 0);
}
// Driver code
int main()
{
int arr[] = { 1, 2, 3, 4, 5 };
int n = sizeof(arr) / sizeof(arr[0]);
// Build segment tree from given array
constructST(arr, n);
// Add 4 to all nodes in index range [0, 3]
updateRange(n, 0, 3, 4);
// Print maximum element in index range [1, 4]
cout << getSum(n, 1, 4);
return 0;
}
Java
// Java implementation of the approach
class GFG
{
static int MAX =1000;
// Ideally, we should not use global variables and large
// constant-sized arrays, we have done it here for simplicity
// To store segment tree
static int tree[] = new int[MAX];
// To store pending updates
static int lazy[] = new int[MAX];
// si -> index of current node in segment tree
// ss and se -> Starting and ending indexes of
// elements for which current nodes stores sum
// us and ue -> starting and ending indexes of update query
// diff -> which we need to add in the range us to ue
static void updateRangeUtil(int si, int ss, int se, int us,
int ue, int diff)
{
// If lazy value is non-zero for current node of segment
// tree, then there are some pending updates. So we need
// to make sure that the pending updates are done before
// making new updates. Because this value may be used by
// parent after recursive calls (See last line of this
// function)
if (lazy[si] != 0)
{
// Make pending updates using value stored in lazy
// nodes
tree[si] += lazy[si];
// Checking if it is not leaf node because if
// it is leaf node then we cannot go further
if (ss != se)
{
// We can postpone updating children we don't
// need their new values now.
// Since we are not yet updating children of si,
// we need to set lazy flags for the children
lazy[si * 2 + 1] += lazy[si];
lazy[si * 2 + 2] += lazy[si];
}
// Set the lazy value for current node as 0 as it
// has been updated
lazy[si] = 0;
}
// Out of range
if (ss > se || ss > ue || se < us)
return;
// Current segment is fully in range
if (ss >= us && se <= ue)
{
// Add the difference to current node
tree[si] += diff;
// Same logic for checking leaf node or not
if (ss != se)
{
// This is where we store values in lazy nodes,
// rather than updating the segment tree itelf
// Since we don't need these updated values now
// we postpone updates by storing values in lazy[]
lazy[si * 2 + 1] += diff;
lazy[si * 2 + 2] += diff;
}
return;
}
// If not completely in range, but overlaps
// recur for children
int mid = (ss + se) / 2;
updateRangeUtil(si * 2 + 1, ss, mid, us, ue, diff);
updateRangeUtil(si * 2 + 2, mid + 1, se, us, ue, diff);
// And use the result of children calls
// to update this node
tree[si] = Math.max(tree[si * 2 + 1], tree[si * 2 + 2]);
}
// Function to update a range of values in segment
// tree
// us and eu -> starting and ending indexes of update query
// ue -> ending index of update query
// diff -> which we need to add in the range us to ue
static void updateRange(int n, int us, int ue, int diff)
{
updateRangeUtil(0, 0, n - 1, us, ue, diff);
}
// A recursive function to get the sum of values in given
// a range of the array. The following are the parameters
// for this function
// si --> Index of the current node in the segment tree
// Initially, 0 is passed as root is always at index 0
// ss & se --> Starting and ending indexes of the
// segment represented by current node
// i.e., tree[si]
// qs & qe --> Starting and ending indexes of query
// range
static int getSumUtil(int ss, int se, int qs, int qe, int si)
{
// If lazy flag is set for current node of segment tree
// then there are some pending updates. So we need to
// make sure that the pending updates are done before
// processing the sub sum query
if (lazy[si] != 0)
{
// Make pending updates to this node. Note that this
// node represents sum of elements in arr[ss..se] and
// all these elements must be increased by lazy[si]
tree[si] += lazy[si];
// Checking if it is not leaf node because if
// it is leaf node then we cannot go further
if (ss != se)
{
// Since we are not yet updating children os si,
// we need to set lazy values for the children
lazy[si * 2 + 1] += lazy[si];
lazy[si * 2 + 2] += lazy[si];
}
// Unset the lazy value for current node as it has
// been updated
lazy[si] = 0;
}
// Out of range
if (ss > se || ss > qe || se < qs)
return 0;
// At this point, we are sure that pending lazy updates
// are done for current node. So we can return value
// (same as it was for a query in our previous post)
// If this segment lies in range
if (ss >= qs && se <= qe)
return tree[si];
// If a part of this segment overlaps with the given
// range
int mid = (ss + se) / 2;
return Math.max(getSumUtil(ss, mid, qs, qe, 2 * si + 1),
getSumUtil(mid + 1, se, qs, qe, 2 * si + 2));
}
// Return sum of elements in range from index qs (query
// start) to qe (query end). It mainly uses getSumUtil()
static int getSum(int n, int qs, int qe)
{
// Check for erroneous input values
if (qs < 0 || qe > n - 1 || qs > qe)
{
System.out.print("Invalid Input");
return -1;
}
return getSumUtil(0, n - 1, qs, qe, 0);
}
// A recursive function that constructs Segment Tree for
// array[ss..se]. si is index of current node in segment
// tree st.
static void constructSTUtil(int arr[], int ss, int se, int si)
{
// out of range as ss can never be greater than se
if (ss > se)
return;
// If there is one element in array, store it in
// current node of segment tree and return
if (ss == se)
{
tree[si] = arr[ss];
return;
}
// If there are more than one elements, then recur
// for left and right subtrees and store the sum
// of values in this node
int mid = (ss + se) / 2;
constructSTUtil(arr, ss, mid, si * 2 + 1);
constructSTUtil(arr, mid + 1, se, si * 2 + 2);
tree[si] = Math.max(tree[si * 2 + 1], tree[si * 2 + 2]);
}
// Function to construct a segment tree from a given array
// This function allocates memory for segment tree and
// calls constructSTUtil() to fill the allocated memory
static void constructST(int arr[], int n)
{
// Fill the allocated memory st
constructSTUtil(arr, 0, n - 1, 0);
}
// Driver code
public static void main(String[] args)
{
int arr[] = { 1, 2, 3, 4, 5 };
int n = arr.length;
// Build segment tree from given array
constructST(arr, n);
// Add 4 to all nodes in index range [0, 3]
updateRange(n, 0, 3, 4);
// Print maximum element in index range [1, 4]
System.out.println(getSum(n, 1, 4));
}
}
/* This code contributed by PrinciRaj1992 */
Python3
# Python3 implementation of the approach
MAX = 1000
# Ideally, we should not use global variables
# and large constant-sized arrays,
# we have done it here for simplicity
# To store segment tree
tree = [0] * MAX;
# To store pending updates
lazy = [0] * MAX;
# si -> index of current node in segment tree
# ss and se -> Starting and ending indexes of
# elements for which current nodes stores sum
# us and ue -> starting and ending indexes of update query
# diff -> which we need to add in the range us to ue
def updateRangeUtil(si, ss, se, us, ue, diff) :
# If lazy value is non-zero for current node
# of segment tree, then there are some
# pending updates. So we need to make sure that
# the pending updates are done before making
# new updates. Because this value may be used by
# parent after recursive calls (See last line of this
# function)
if (lazy[si] != 0) :
# Make pending updates using value
# stored in lazy nodes
tree[si] += lazy[si];
# Checking if it is not leaf node because if
# it is leaf node then we cannot go further
if (ss != se) :
# We can postpone updating children
# we don't need their new values now.
# Since we are not yet updating children of si,
# we need to set lazy flags for the children
lazy[si * 2 + 1] += lazy[si];
lazy[si * 2 + 2] += lazy[si];
# Set the lazy value for current node
# as 0 as it has been updated
lazy[si] = 0;
# Out of range
if (ss > se or ss > ue or se < us) :
return;
# Current segment is fully in range
if (ss >= us and se <= ue) :
# Add the difference to current node
tree[si] += diff;
# Same logic for checking leaf node or not
if (ss != se) :
# This is where we store values in lazy nodes,
# rather than updating the segment tree itelf
# Since we don't need these updated values now
# we postpone updates by storing values in lazy[]
lazy[si * 2 + 1] += diff;
lazy[si * 2 + 2] += diff;
return;
# If not completely in range, but overlaps
# recur for children
mid = (ss + se) // 2;
updateRangeUtil(si * 2 + 1, ss,
mid, us, ue, diff);
updateRangeUtil(si * 2 + 2, mid + 1,
se, us, ue, diff);
# And use the result of children calls
# to update this node
tree[si] = max(tree[si * 2 + 1],
tree[si * 2 + 2]);
# Function to update a range of values
# in segment tree
# us and eu -> starting and ending
# indexes of update query
# ue -> ending index of update query
# diff -> which we need to add in the range us to ue
def updateRange(n, us, ue, diff) :
updateRangeUtil(0, 0, n - 1, us, ue, diff);
# A recursive function to get the sum of values
# in a given range of the array. The following
# are the parameters for this function
# si --> Index of the current node in the segment tree
# Initially, 0 is passed as root is always at index 0
# ss & se --> Starting and ending indexes of the
# segment represented by current node
# i.e., tree[si]
# qs & qe --> Starting and ending indexes of query
# range
def getSumUtil(ss, se, qs, qe, si) :
# If lazy flag is set for current node
# of segment tree then there are some
# pending updates. So we need to make sure
# that the pending updates are done before
# processing the sub sum query
if (lazy[si] != 0) :
# Make pending updates to this node.
# Note that this node represents sum of
# elements in arr[ss..se] and all these
# elements must be increased by lazy[si]
tree[si] += lazy[si];
# Checking if it is not leaf node because if
# it is leaf node then we cannot go further
if (ss != se) :
# Since we are not yet updating children os si,
# we need to set lazy values for the children
lazy[si * 2 + 1] += lazy[si];
lazy[si * 2 + 2] += lazy[si];
# Unset the lazy value for current node
# as it has been updated
lazy[si] = 0;
# Out of range
if (ss > se or ss > qe or se < qs) :
return 0;
# At this point, we are sure that pending lazy updates
# are done for current node. So we can return value
# (same as it was for a query in our previous post)
# If this segment lies in range
if (ss >= qs and se <= qe) :
return tree[si];
# If a part of this segment overlaps
# with the given range
mid = (ss + se) // 2;
return max(getSumUtil(ss, mid, qs, qe, 2 * si + 1),
getSumUtil(mid + 1, se, qs, qe, 2 * si + 2));
# Return sum of elements in range from index qs (query
# start) to qe (query end). It mainly uses getSumUtil()
def getSum(n, qs, qe) :
# Check for erroneous input values
if (qs < 0 or qe > n - 1 or qs > qe) :
print("Invalid Input", end = "");
return -1;
return getSumUtil(0, n - 1, qs, qe, 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, si) :
# out of range as ss can never be
# greater than se
if (ss > se) :
return;
# If there is one element in array,
# store it in current node of segment
# tree and return
if (ss == se) :
tree[si] = arr[ss];
return;
# If there are more than one elements,
# then recur for left and right subtrees
# and store the sum of values in this node
mid = (ss + se) // 2;
constructSTUtil(arr, ss, mid, si * 2 + 1);
constructSTUtil(arr, mid + 1, se, si * 2 + 2);
tree[si] = max(tree[si * 2 + 1], tree[si * 2 + 2]);
# Function to construct a segment tree
# from a given array. This function allocates
# memory for segment tree and calls
# constructSTUtil() to fill the allocated memory
def constructST(arr, n) :
# Fill the allocated memory st
constructSTUtil(arr, 0, n - 1, 0);
# Driver code
if __name__ == "__main__" :
arr = [ 1, 2, 3, 4, 5 ];
n = len(arr) ;
# Build segment tree from given array
constructST(arr, n);
# Add 4 to all nodes in index range [0, 3]
updateRange(n, 0, 3, 4);
# Print maximum element in index range [1, 4]
print(getSum(n, 1, 4));
# This code is contributed by AnkitRai01
C#
// C# implementation of the approach
using System;
class GFG
{
static int MAX =1000;
// Ideally, we should not use global variables and large
// constant-sized arrays, we have done it here for simplicity
// To store segment tree
static int []tree = new int[MAX];
// To store pending updates
static int []lazy = new int[MAX];
// si -> index of current node in segment tree
// ss and se -> Starting and ending indexes of
// elements for which current nodes stores sum
// us and ue -> starting and ending indexes of update query
// diff -> which we need to add in the range us to ue
static void updateRangeUtil(int si, int ss, int se, int us,
int ue, int diff)
{
// If lazy value is non-zero for current node of segment
// tree, then there are some pending updates. So we need
// to make sure that the pending updates are done before
// making new updates. Because this value may be used by
// parent after recursive calls (See last line of this
// function)
if (lazy[si] != 0)
{
// Make pending updates using value stored in lazy
// nodes
tree[si] += lazy[si];
// Checking if it is not leaf node because if
// it is leaf node then we cannot go further
if (ss != se)
{
// We can postpone updating children we don't
// need their new values now.
// Since we are not yet updating children of si,
// we need to set lazy flags for the children
lazy[si * 2 + 1] += lazy[si];
lazy[si * 2 + 2] += lazy[si];
}
// Set the lazy value for current node as 0 as it
// has been updated
lazy[si] = 0;
}
// Out of range
if (ss > se || ss > ue || se < us)
return;
// Current segment is fully in range
if (ss >= us && se <= ue)
{
// Add the difference to current node
tree[si] += diff;
// Same logic for checking leaf node or not
if (ss != se)
{
// This is where we store values in lazy nodes,
// rather than updating the segment tree itelf
// Since we don't need these updated values now
// we postpone updates by storing values in lazy[]
lazy[si * 2 + 1] += diff;
lazy[si * 2 + 2] += diff;
}
return;
}
// If not completely in range, but overlaps
// recur for children
int mid = (ss + se) / 2;
updateRangeUtil(si * 2 + 1, ss, mid, us, ue, diff);
updateRangeUtil(si * 2 + 2, mid + 1, se, us, ue, diff);
// And use the result of children calls
// to update this node
tree[si] = Math.Max(tree[si * 2 + 1], tree[si * 2 + 2]);
}
// Function to update a range of values in segment
// tree
// us and eu -> starting and ending indexes of update query
// ue -> ending index of update query
// diff -> which we need to add in the range us to ue
static void updateRange(int n, int us, int ue, int diff)
{
updateRangeUtil(0, 0, n - 1, us, ue, diff);
}
// A recursive function to get the sum of values in given
// a range of the array. The following are the parameters
// for this function
// si --> Index of the current node in the segment tree
// Initially, 0 is passed as root is always at index 0
// ss & se --> Starting and ending indexes of the
// segment represented by current node
// i.e., tree[si]
// qs & qe --> Starting and ending indexes of query
// range
static int getSumUtil(int ss, int se, int qs, int qe, int si)
{
// If lazy flag is set for current node of segment tree
// then there are some pending updates. So we need to
// make sure that the pending updates are done before
// processing the sub sum query
if (lazy[si] != 0)
{
// Make pending updates to this node. Note that this
// node represents sum of elements in arr[ss..se] and
// all these elements must be increased by lazy[si]
tree[si] += lazy[si];
// Checking if it is not leaf node because if
// it is leaf node then we cannot go further
if (ss != se)
{
// Since we are not yet updating children os si,
// we need to set lazy values for the children
lazy[si * 2 + 1] += lazy[si];
lazy[si * 2 + 2] += lazy[si];
}
// Unset the lazy value for current node as it has
// been updated
lazy[si] = 0;
}
// Out of range
if (ss > se || ss > qe || se < qs)
return 0;
// At this point, we are sure that pending lazy updates
// are done for current node. So we can return value
// (same as it was for a query in our previous post)
// If this segment lies in range
if (ss >= qs && se <= qe)
return tree[si];
// If a part of this segment overlaps with the given
// range
int mid = (ss + se) / 2;
return Math.Max(getSumUtil(ss, mid, qs, qe, 2 * si + 1),
getSumUtil(mid + 1, se, qs, qe, 2 * si + 2));
}
// Return sum of elements in range from index qs (query
// start) to qe (query end). It mainly uses getSumUtil()
static int getSum(int n, int qs, int qe)
{
// Check for erroneous input values
if (qs < 0 || qe > n - 1 || qs > qe)
{
Console.Write("Invalid Input");
return -1;
}
return getSumUtil(0, n - 1, qs, qe, 0);
}
// A recursive function that constructs Segment Tree for
// array[ss..se]. si is index of current node in segment
// tree st.
static void constructSTUtil(int []arr, int ss, int se, int si)
{
// out of range as ss can never be greater than se
if (ss > se)
return;
// If there is one element in array, store it in
// current node of segment tree and return
if (ss == se)
{
tree[si] = arr[ss];
return;
}
// If there are more than one elements, then recur
// for left and right subtrees and store the sum
// of values in this node
int mid = (ss + se) / 2;
constructSTUtil(arr, ss, mid, si * 2 + 1);
constructSTUtil(arr, mid + 1, se, si * 2 + 2);
tree[si] = Math.Max(tree[si * 2 + 1], tree[si * 2 + 2]);
}
// Function to construct a segment tree from a given array
// This function allocates memory for segment tree and
// calls constructSTUtil() to fill the allocated memory
static void constructST(int []arr, int n)
{
// Fill the allocated memory st
constructSTUtil(arr, 0, n - 1, 0);
}
// Driver code
public static void Main(String[] args)
{
int []arr = { 1, 2, 3, 4, 5 };
int n = arr.Length;
// Build segment tree from given array
constructST(arr, n);
// Add 4 to all nodes in index range [0, 3]
updateRange(n, 0, 3, 4);
// Print maximum element in index range [1, 4]
Console.WriteLine(getSum(n, 1, 4));
}
}
// This code has been contributed by 29AjayKumar
输出:
8