📌  相关文章
📜  细分树|设置1(给定范围的总和)

📅  最后修改于: 2021-04-17 12:55:06             🧑  作者: Mango

让我们考虑以下问题以理解段树。
我们有一个数组arr [0。 。 。 n-1]。我们应该能够
1找到从索引l到r的元素总和,其中0 <= l <= r <= n-1
2将数组的指定元素的值更改为新值x。我们需要做arr [i] = x,其中0 <= i <= n-1。

一个简单的解决方案是运行从l到r的循环,并计算给定范围内的元素之和。要更新值,只需做arr [i] = x。第一次操作花费O(n)时间,第二次操作花费O(1)时间。
另一个解决方案是创建另一个数组,并将从开始到i的和存储在此数组的第i个索引处。现在可以以O(1)的时间计算给定范围的总和,但是更新操作现在需要O(n)的时间。如果查询操作的数量很大且更新很少,则此方法效果很好。
如果查询次数和更新次数相等怎么办?给定数组后,是否可以在O(log n)时间内执行这两个操作?我们可以使用细分树在O(Logn)时间内完成这两项操作。
段树的表示
1.叶节点是输入数组的元素。
2.每个内部节点代表叶节点的一些合并。对于不同的问题,合并可能会有所不同。对于此问题,合并是节点下的叶子之和。
树的数组表示形式用于表示段树。对于索引i处的每个节点,左子节点在索引2 * i + 1处,右子节点在索引2 * i + 2处,父节点在索引处2 * i + 2处。

st1

上段树在内存中的外观如何?
像堆一样,段树也表示为数组。此处的区别在于,它不是完整的二叉树。它是一棵完整的二叉树(每个节点都有0或2个子节点),并且除最后一个级别外,所有级别都已填充。与堆不同,最后一级在节点之间可能有间隙。以下是上图的细分树数组中的值。

伪值永远不会访问,也没有用。由于简单的数组表示,这会浪费一些空间。我们可以使用一些聪明的实现来优化这种浪费,但是求和和更新的代码变得更加复杂。
从给定数组构造细分树
我们从一个段arr [0开始。 。 。 n-1]。每次我们将当前段分成两半(如果尚未将其变成长度为1的段),然后在这两个半段上调用相同的过程,对于每个这样的段,我们将和存储在相应的节点中。
除最后一个级别外,已构建的段树的所有级别都将被完全填充。而且,该树将是完整的二叉树,因为我们总是在每个级别将分段分为两半。由于构造的树始终是具有n个叶子的完整二叉树,因此将有n-1个内部节点。因此,节点总数将为2 * n –1。请注意,这不包括虚拟节点。
表示段树的数组的总大小是多少?
如果n是2的幂,则没有虚拟节点。因此,段树的大小为2n-1(n个叶节点和n-1)个内部节点。如果n不是2的幂,则树的大小将为2 * x – 1,其中x是大于n的2的最小幂。例如,当n = 10时,表示段树的数组的大小为2 * 16-1 = 31。
关于大小的另一种解释是基于heignt。段树的高度将为

ST2

。由于树是使用数组表示的,并且必须保持父索引和子索引之间的关系,因此分配给段树的内存大小将是

st3


查询给定范围的总和
构造树后,如何使用构造的分段树获取总和。以下是获取元素总和的算法。

int getSum(node, l, r) 
{
   if the range of the node is within l and r
        return value in the node
   else if the range of the node is completely outside l and r
        return 0
   else
    return getSum(node's left child, l, r) + 
           getSum(node's right child, l, r)
}

更新值
像树构建和查询操作一样,更新也可以递归完成。给我们一个需要更新的索引。令diff为要添加的值。我们从段树的根开始,将diff添加到在其范围内具有给定索引的所有节点。如果节点在其范围内没有给定的索引,则我们不会对该节点进行任何更改。
执行:
以下是段树的实现。该程序为任何给定的数组实现了段树的构造。它还实现了查询和更新操作。

C++
// C++ program to show segment tree operations like construction, query
// and update
#include 
using namespace std;
 
// A utility function to get the middle index from corner indexes.
int getMid(int s, int e) { return s + (e -s)/2; }
 
/* A recursive function to get the sum of values in the given range
    of the array. The following are parameters for this function.
 
    st --> Pointer to segment tree
    si --> Index of 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., st[si]
    qs & qe --> Starting and ending indexes of query range */
int getSumUtil(int *st, int ss, int se, int qs, int qe, int si)
{
    // If segment of this node is a part of given range, then return
    // the sum of the segment
    if (qs <= ss && qe >= se)
        return st[si];
 
    // If segment of this node is outside the given range
    if (se < qs || ss > qe)
        return 0;
 
    // If a part of this segment overlaps with the given range
    int mid = getMid(ss, se);
    return getSumUtil(st, ss, mid, qs, qe, 2*si+1) +
        getSumUtil(st, mid+1, se, qs, qe, 2*si+2);
}
 
/* A recursive function to update the nodes which have the given
index in their range. The following are parameters
    st, si, ss and se are same as getSumUtil()
    i --> index of the element to be updated. This index is
            in the input array.
diff --> Value to be added to all nodes which have i in range */
void updateValueUtil(int *st, int ss, int se, int i, int diff, int si)
{
    // Base Case: If the input index lies outside the range of
    // this segment
    if (i < ss || i > se)
        return;
 
    // If the input index is in range of this node, then update
    // the value of the node and its children
    st[si] = st[si] + diff;
    if (se != ss)
    {
        int mid = getMid(ss, se);
        updateValueUtil(st, ss, mid, i, diff, 2*si + 1);
        updateValueUtil(st, mid+1, se, i, diff, 2*si + 2);
    }
}
 
// The function to update a value in input array and segment tree.
// It uses updateValueUtil() to update the value in segment tree
void updateValue(int arr[], int *st, int n, int i, int new_val)
{
    // Check for erroneous input index
    if (i < 0 || i > n-1)
    {
        cout<<"Invalid Input";
        return;
    }
 
    // Get the difference between new value and old value
    int diff = new_val - arr[i];
 
    // Update the value in array
    arr[i] = new_val;
 
    // Update the values of nodes in segment tree
    updateValueUtil(st, 0, n-1, i, diff, 0);
}
 
// Return sum of elements in range from index qs (quey start)
// to qe (query end). It mainly uses getSumUtil()
int getSum(int *st, int n, int qs, int qe)
{
    // Check for erroneous input values
    if (qs < 0 || qe > n-1 || qs > qe)
    {
        cout<<"Invalid Input";
        return -1;
    }
 
    return getSumUtil(st, 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
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 sum of values in this node
    int mid = getMid(ss, se);
    st[si] = 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 and calls constructSTUtil() to
fill the allocated memory */
int *constructST(int arr[], int n)
{
    // Allocate memory for the segment tree
 
    //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 program to test above functions
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 sum of values in array from index 1 to 3
    cout<<"Sum of values in given range = "<C
// C program to show segment tree operations like construction, query
// and update
#include 
#include 
 
// A utility function to get the middle index from corner indexes.
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
    si    --> Index of 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., st[si]
    qs & qe  --> Starting and ending indexes of query range */
int getSumUtil(int *st, int ss, int se, int qs, int qe, int si)
{
    // If segment of this node is a part of given range, then return
    // the sum of the segment
    if (qs <= ss && qe >= se)
        return st[si];
 
    // If segment of this node is outside the given range
    if (se < qs || ss > qe)
        return 0;
 
    // If a part of this segment overlaps with the given range
    int mid = getMid(ss, se);
    return getSumUtil(st, ss, mid, qs, qe, 2*si+1) +
           getSumUtil(st, mid+1, se, qs, qe, 2*si+2);
}
 
/* A recursive function to update the nodes which have the given
   index in their range. The following are parameters
    st, si, ss and se are same as getSumUtil()
    i    --> index of the element to be updated. This index is
             in the input array.
   diff --> Value to be added to all nodes which have i in range */
void updateValueUtil(int *st, int ss, int se, int i, int diff, int si)
{
    // Base Case: If the input index lies outside the range of
    // this segment
    if (i < ss || i > se)
        return;
 
    // If the input index is in range of this node, then update
    // the value of the node and its children
    st[si] = st[si] + diff;
    if (se != ss)
    {
        int mid = getMid(ss, se);
        updateValueUtil(st, ss, mid, i, diff, 2*si + 1);
        updateValueUtil(st, mid+1, se, i, diff, 2*si + 2);
    }
}
 
// The function to update a value in input array and segment tree.
// It uses updateValueUtil() to update the value in segment tree
void updateValue(int arr[], int *st, int n, int i, int new_val)
{
    // Check for erroneous input index
    if (i < 0 || i > n-1)
    {
        printf("Invalid Input");
        return;
    }
 
    // Get the difference between new value and old value
    int diff = new_val - arr[i];
 
    // Update the value in array
    arr[i] = new_val;
 
    // Update the values of nodes in segment tree
    updateValueUtil(st, 0, n-1, i, diff, 0);
}
 
// Return sum of elements in range from index qs (quey start)
// to qe (query end).  It mainly uses getSumUtil()
int getSum(int *st, 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(st, 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
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 sum of values in this node
    int mid = getMid(ss, se);
    st[si] =  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 and calls constructSTUtil() to
   fill the allocated memory */
int *constructST(int arr[], int n)
{
    // Allocate memory for the segment tree
 
    //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 program to test above functions
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 sum of values in array from index 1 to 3
    printf("Sum of values in given range = %dn",
            getSum(st, n, 1, 3));
 
    // Update: set arr[1] = 10 and update corresponding
    // segment tree nodes
    updateValue(arr, st, n, 1, 10);
 
    // Find sum after the value is updated
    printf("Updated sum of values in given range = %dn",
             getSum(st, n, 1, 3));
    return 0;
}


Java
// Java Program to show segment tree operations like construction,
// query and update
class SegmentTree
{
    int st[]; // The array that stores segment tree nodes
 
    /* Constructor to construct segment tree from given array. This
       constructor  allocates memory for segment tree and calls
       constructSTUtil() to  fill the allocated memory */
    SegmentTree(int arr[], int n)
    {
        // Allocate memory for segment tree
        //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;
 
        st = new int[max_size]; // Memory allocation
 
        constructSTUtil(arr, 0, n - 1, 0);
    }
 
    // A utility function to get the middle index from corner indexes.
    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
      si    --> Index of 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., st[si]
      qs & qe  --> Starting and ending indexes of query range */
    int getSumUtil(int ss, int se, int qs, int qe, int si)
    {
        // If segment of this node is a part of given range, then return
        // the sum of the segment
        if (qs <= ss && qe >= se)
            return st[si];
 
        // If segment of this node is outside the given range
        if (se < qs || ss > qe)
            return 0;
 
        // If a part of this segment overlaps with the given range
        int mid = getMid(ss, se);
        return getSumUtil(ss, mid, qs, qe, 2 * si + 1) +
                getSumUtil(mid + 1, se, qs, qe, 2 * si + 2);
    }
 
    /* A recursive function to update the nodes which have the given
       index in their range. The following are parameters
        st, si, ss and se are same as getSumUtil()
        i    --> index of the element to be updated. This index is in
                 input array.
       diff --> Value to be added to all nodes which have i in range */
    void updateValueUtil(int ss, int se, int i, int diff, int si)
    {
        // Base Case: If the input index lies outside the range of
        // this segment
        if (i < ss || i > se)
            return;
 
        // If the input index is in range of this node, then update the
        // value of the node and its children
        st[si] = st[si] + diff;
        if (se != ss) {
            int mid = getMid(ss, se);
            updateValueUtil(ss, mid, i, diff, 2 * si + 1);
            updateValueUtil(mid + 1, se, i, diff, 2 * si + 2);
        }
    }
 
    // The function to update a value in input array and segment tree.
   // It uses updateValueUtil() to update the value in segment tree
    void updateValue(int arr[], int n, int i, int new_val)
    {
        // Check for erroneous input index
        if (i < 0 || i > n - 1) {
            System.out.println("Invalid Input");
            return;
        }
 
        // Get the difference between new value and old value
        int diff = new_val - arr[i];
 
        // Update the value in array
        arr[i] = new_val;
 
        // Update the values of nodes in segment tree
        updateValueUtil(0, n - 1, i, diff, 0);
    }
 
    // Return sum of elements in range from index qs (quey 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) {
            System.out.println("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
    int constructSTUtil(int arr[], int ss, int se, 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 sum of values in this node
        int mid = getMid(ss, se);
        st[si] = constructSTUtil(arr, ss, mid, si * 2 + 1) +
                 constructSTUtil(arr, mid + 1, se, si * 2 + 2);
        return st[si];
    }
 
    // Driver program to test above functions
    public static void main(String args[])
    {
        int arr[] = {1, 3, 5, 7, 9, 11};
        int n = arr.length;
        SegmentTree  tree = new SegmentTree(arr, n);
 
        // Build segment tree from given array
 
        // Print sum of values in array from index 1 to 3
        System.out.println("Sum of values in given range = " +
                           tree.getSum(n, 1, 3));
 
        // Update: set arr[1] = 10 and update corresponding segment
        // tree nodes
        tree.updateValue(arr, n, 1, 10);
 
        // Find sum after the value is updated
        System.out.println("Updated sum of values in given range = " +
                tree.getSum(n, 1, 3));
    }
}
//This code is contributed by Ankur Narain Verma


Python3
# Python3 program to show segment tree operations like
# construction, query and update
from math import ceil, log2;
 
# A utility function to get the
# middle index from corner indexes.
def getMid(s, e) :
    return s + (e -s) // 2;
 
""" A recursive function to get the sum of values
    in the given range of the array. The following
    are parameters for this function.
 
    st --> Pointer to segment tree
    si --> Index of 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., st[si]
    qs & qe --> Starting and ending indexes of query range """
def getSumUtil(st, ss, se, qs, qe, si) :
 
    # If segment of this node is a part of given range,
    # then return the sum of the segment
    if (qs <= ss and qe >= se) :
        return st[si];
 
    # If segment of this node is
    # outside the given range
    if (se < qs or ss > qe) :
        return 0;
 
    # If a part of this segment overlaps
    # with the given range
    mid = getMid(ss, se);
     
    return getSumUtil(st, ss, mid, qs, qe, 2 * si + 1) +
           getSumUtil(st, mid + 1, se, qs, qe, 2 * si + 2);
 
""" A recursive function to update the nodes
which have the given index in their range.
The following are parameters st, si, ss and se
are same as getSumUtil()
i --> index of the element to be updated.
      This index is in the input array.
diff --> Value to be added to all nodes
which have i in range """
def updateValueUtil(st, ss, se, i, diff, si) :
 
    # Base Case: If the input index lies
    # outside the range of this segment
    if (i < ss or i > se) :
        return;
 
    # If the input index is in range of this node,
    # then update the value of the node and its children
    st[si] = st[si] + diff;
     
    if (se != ss) :
     
        mid = getMid(ss, se);
        updateValueUtil(st, ss, mid, i,
                        diff, 2 * si + 1);
        updateValueUtil(st, mid + 1, se, i,
                         diff, 2 * si + 2);
 
# The function to update a value in input array
# and segment tree. It uses updateValueUtil()
# to update the value in segment tree
def updateValue(arr, st, n, i, new_val) :
 
    # Check for erroneous input index
    if (i < 0 or i > n - 1) :
         
        print("Invalid Input", end = "");
        return;
 
    # Get the difference between
    # new value and old value
    diff = new_val - arr[i];
 
    # Update the value in array
    arr[i] = new_val;
 
    # Update the values of nodes in segment tree
    updateValueUtil(st, 0, n - 1, i, diff, 0);
 
# Return sum of elements in range from
# index qs (quey start) to qe (query end).
# It mainly uses getSumUtil()
def getSum(st, 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(st, 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, 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 sum of values in this node
    mid = getMid(ss, se);
     
    st[si] = 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 and calls constructSTUtil() to
fill the allocated memory """
def constructST(arr, n) :
 
    # Allocate memory for the segment tree
 
    # Height of segment tree
    x = (int)(ceil(log2(n)));
 
    # Maximum size of segment tree
    max_size = 2 * (int)(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);
 
    # Print sum of values in array from index 1 to 3
    print("Sum of values in given range = ",
                       getSum(st, n, 1, 3));
 
    # Update: set arr[1] = 10 and update
    # corresponding segment tree nodes
    updateValue(arr, st, n, 1, 10);
 
    # Find sum after the value is updated
    print("Updated sum of values in given range = ",
                     getSum(st, n, 1, 3), end = "");
     
# This code is contributed by AnkitRai01


C#
// C# Program to show segment tree
// operations like construction,
// query and update
using System;
 
class SegmentTree
{
    int []st; // The array that stores segment tree nodes
 
    /* Constructor to construct segment
    tree from given array. This constructor
    allocates memory for segment tree and calls
    constructSTUtil() to fill the allocated memory */
    SegmentTree(int []arr, int n)
    {
        // Allocate memory for segment tree
        //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;
 
        st = new int[max_size]; // Memory allocation
 
        constructSTUtil(arr, 0, n - 1, 0);
    }
 
    // A utility function to get the
    // middle index from corner indexes.
    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
    si --> Index of 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., st[si]
    qs & qe --> Starting and ending indexes of query range */
    int getSumUtil(int ss, int se, int qs, int qe, int si)
    {
        // If segment of this node is a part
        // of given range, then return
        // the sum of the segment
        if (qs <= ss && qe >= se)
            return st[si];
 
        // If segment of this node is
        // outside the given range
        if (se < qs || ss > qe)
            return 0;
 
        // If a part of this segment
        // overlaps with the given range
        int mid = getMid(ss, se);
        return getSumUtil(ss, mid, qs, qe, 2 * si + 1) +
                getSumUtil(mid + 1, se, qs, qe, 2 * si + 2);
    }
 
    /* A recursive function to update
    the nodes which have the given
    index in their range. The following
    are parameters st, si, ss and se
    are same as getSumUtil() i --> index
    of the element to be updated. This
    index is in input array. diff --> Value
    to be added to all nodes which have i in range */
    void updateValueUtil(int ss, int se, int i,
                                int diff, int si)
    {
        // Base Case: If the input index
        // lies outside the range of this segment
        if (i < ss || i > se)
            return;
 
        // If the input index is in range of
        // this node, then update the value
        // of the node and its children
        st[si] = st[si] + diff;
        if (se != ss)
        {
            int mid = getMid(ss, se);
            updateValueUtil(ss, mid, i, diff, 2 * si + 1);
            updateValueUtil(mid + 1, se, i, diff, 2 * si + 2);
        }
    }
 
    // The function to update a value
    // in input array and segment tree.
    // It uses updateValueUtil() to
    // update the value in segment tree
    void updateValue(int []arr, int n, int i, int new_val)
    {
        // Check for erroneous input index
        if (i < 0 || i > n - 1)
        {
            Console.WriteLine("Invalid Input");
            return;
        }
 
        // Get the difference between
        // new value and old value
        int diff = new_val - arr[i];
         
        // Update the value in array
        arr[i] = new_val;
 
        // Update the values of nodes in segment tree
        updateValueUtil(0, n - 1, i, diff, 0);
    }
 
    // Return sum of elements in range
    // from index qs (quey 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)
        {
            Console.WriteLine("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
    int constructSTUtil(int []arr, int ss, int se, 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 sum of values in this node
        int mid = getMid(ss, se);
        st[si] = constructSTUtil(arr, ss, mid, si * 2 + 1) +
                constructSTUtil(arr, mid + 1, se, si * 2 + 2);
        return st[si];
    }
 
    // Driver code
    public static void Main()
    {
        int []arr = {1, 3, 5, 7, 9, 11};
        int n = arr.Length;
        SegmentTree tree = new SegmentTree(arr, n);
 
        // Build segment tree from given array
 
        // Print sum of values in array from index 1 to 3
        Console.WriteLine("Sum of values in given range = " +
                                        tree.getSum(n, 1, 3));
 
        // Update: set arr[1] = 10 and update
        // corresponding segment tree nodes
        tree.updateValue(arr, n, 1, 10);
 
        // Find sum after the value is updated
        Console.WriteLine("Updated sum of values in given range = " +
                tree.getSum(n, 1, 3));
    }
}
 
/* This code contributed by PrinciRaj1992 */


输出:

Sum of values in given range = 15
Updated sum of values in given range = 22

时间复杂度:
树构建的时间复杂度为O(n)。总共有2n-1个节点,并且在树结构中每个节点的值仅计算一次。
查询的时间复杂度为O(Logn)。要查询总和,我们在每个级别最多处理四个节点,并且级别数为O(Logn)。
更新的时间复杂度也是O(Logn)。要更新叶值,我们在每个级别处理一个节点,级别数为O(Logn)。
细分树|设置2(范围最小查询)

参考:
IIT Kanpur纸。