📌  相关文章
📜  细分树|设置2(带有节点更新的范围最大查询)

📅  最后修改于: 2021-04-17 09:40:11             🧑  作者: Mango

给定数组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 TreeO(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