📜  迭代段树(范围最小查询)

📅  最后修改于: 2021-04-17 08:14:47             🧑  作者: Mango

我们已经讨论了递归段树的实现。在这篇文章中,讨论了迭代实现。

让我们考虑以下问题,了解细分树。

我们有一个数组arr [0。 。 。 n-1]。我们应该能够
1找到从索引l到r的最小元素,其中0 <= l <= r <= n-1
2将数组的指定元素的值更改为新值x。我们需要做arr [i] = x,其中0 <= i <= n-1。

例子:

Input : 2, 6, 7, 5, 18, 86, 54, 2
        minimum(2, 7)  
        update(3, 4)
        minimum(2, 6) 
Output : Minimum in range 2 to 7 is 2.
         Minimum in range 2 to 6 is 4.

段树的迭代版本主要使用以下事实:对于索引i,树中的左子节点= 2 * i,右子节点= 2 * i + 1。可以通过parent = i / 2找到分段树数组中索引i的父级。因此,我们可以轻松地在树的各个层次上上下移动。首先,我们计算范围内的最小值,同时构造从叶节点开始并逐层爬升的树。在处理查询以查找范围内的最小值时,我们使用相同的概念。由于在最坏的情况下有(log n)个级别,因此查询花费log n时间。为了将特定索引更新为给定值,我们开始从叶节点开始更新段树,并通过在每次迭代中逐步上移级别来更新受当前节点更新影响的所有那些节点。更新也需要花费n倍的时间,因为我们必须从叶节点开始更新所有级别,在该叶节点处,我们将根据用户指定的确切索引来更新确切值。

C++
// CPP Program to implement iterative segment
// tree.
#include 
#define ll long long
  
using namespace std;
  
void construct_segment_tree(vector& segtree, 
                           vector &a, int n)
{
    // assign values to leaves of the segment tree
    for (int i = 0; i < n; i++) 
        segtree[n + i] = a[i];    
  
    /* assign values to internal nodes
      to compute minimum in a given range */
    for (int i = n - 1; i >= 1; i--)
        segtree[i] = min(segtree[2 * i], 
                         segtree[2 * i + 1]);
}
  
void update(vector& segtree, int pos, int value, 
                                               int n)
{
    // change the index to leaf node first
    pos += n;
  
    // update the value at the leaf node
    // at the exact index
    segtree[pos] = value;
  
    while (pos > 1) {
  
        // move up one level at a time in the tree
        pos >>= 1;
  
        // update the values in the nodes in 
        // the next higher level
        segtree[pos] = min(segtree[2 * pos],
                           segtree[2 * pos + 1]);
    }
}
  
int range_query(vector& segtree, int left, int 
                                      right, int n)
{
    /*  Basically the left and right indices will move
        towards right and left respectively and with
        every each next higher level and compute the 
        minimum at each height. */
    // change the index to leaf node first
    left += n;
    right += n;
  
    // initialize minimum to a very high value
    int mi = (int)1e9;
  
    while (left < right) {
  
        // if left index in odd
        if (left & 1) {
            mi = min(mi, segtree[left]);
  
            // make left index even
            left++;
        }
  
        // if right index in odd
        if (right & 1) {
  
            // make right index even
            right--;
  
            mi = min(mi, segtree[right]);
        }
  
        // move to the next higher level
        left /= 2;
        right /= 2;
    }
    return mi;
}
  
// Driver code
int main()
{
    vector a = { 2, 6, 10, 4, 7, 28, 9, 11, 6, 33 };
    int n = a.size();
   
    /* Construct the segment tree by assigning 
       the values to the internal nodes*/
    vector segtree(2 * n);
    construct_segment_tree(segtree, a, n);
  
    // compute minimum in the range left to right
    int left = 0, right = 5;
    cout << "Minimum in range " << left << " to " 
         << right << " is "<< range_query(segtree, left, 
                                  right + 1, n) << "\n";
  
    // update the value of index 3 to 1
    int index = 3, value = 1;
  
    // a[3] = 1;
    // Contents of array : {2, 6, 10, 1, 7, 28, 9, 11, 6, 33}
    update(segtree, index, value, n); // point update
  
    // compute minimum in the range left to right
    left = 2, right = 6;
    cout << "Minimum in range " << left << " to "
         << right << " is " << range_query(segtree, 
                      left, right + 1, n) << "\n";
  
    return 0;
}


Java
// Java Program to implement iterative segment 
// tree. 
import java.io.*;
import java.util.*;
  
class GFG 
{
  
    static void construct_segment_tree(int[] segtree, 
                                        int[] a, int n)
    {
          
        // assign values to leaves of the segment tree
        for (int i = 0; i < n; i++)
            segtree[n + i] = a[i];
  
        /*
        * assign values to internal nodes
        * to compute minimum in a given range
        */
        for (int i = n - 1; i >= 1; i--)
            segtree[i] = Math.min(segtree[2 * i], segtree[2 * i + 1]);
    }
  
    static void update(int[] segtree, int pos, int value, int n)
    {
  
        // change the index to leaf node first
        pos += n;
  
        // update the value at the leaf node
        // at the exact index
        segtree[pos] = value;
  
        while (pos > 1) 
        {
  
            // move up one level at a time in the tree
            pos >>= 1;
  
            // update the values in the nodes in
            // the next higher level
            segtree[pos] = Math.min(segtree[2 * pos], 
                                segtree[2 * pos + 1]);
        }
    }
  
    static int range_query(int[] segtree, int left, 
                           int right, int n) 
    {
          
        /*
        * Basically the left and right indices will move
        * towards right and left respectively and with
        * every each next higher level and compute the
        * minimum at each height. */
        // change the index to leaf node first
        left += n;
        right += n;
  
        // initialize minimum to a very high value
        int mi = (int) 1e9;
  
        while (left < right) 
        {
  
            // if left index in odd
            if ((left & 1) == 1)
            {
                mi = Math.min(mi, segtree[left]);
  
                // make left index even
                left++;
            }
  
            // if right index in odd
            if ((right & 1) == 1) 
            {
  
                // make right index even
                right--;
  
                mi = Math.min(mi, segtree[right]);
            }
  
            // move to the next higher level
            left /= 2;
            right /= 2;
        }
        return mi;
    }
  
    // Driver Code
    public static void main(String[] args)
    {
        int[] a = {2, 6, 10, 4, 7, 28, 9, 11, 6, 33};
        int n = a.length;
  
        /* 
        * Construct the segment tree by assigning
        * the values to the internal nodes
        */
        int[] segtree = new int[2 * n];
        construct_segment_tree(segtree, a, n);
  
        // compute minimum in the range left to right 
        int left = 0, right = 5;
        System.out.printf("Minimum in range %d to %d is %d\n", 
                           left, right, range_query(segtree,
                           left, right + 1, n));
  
        // update the value of index 3 to 1 
        int index = 3, value = 1;
          
        // a[3] = 1; 
        // Contents of array : {2, 6, 10, 1, 7, 28, 9, 11, 6, 33}
        update(segtree, index, value, n); // point update
  
        // compute minimum in the range left to right
        left = 2;
        right = 6;
        System.out.printf("Minimum in range %d to %d is %d\n", 
                           left, right, range_query(segtree, 
                           left, right + 1, n));
    }
}
  
// This code is contributed by
// sanjeev2552


Python3
# Python3 program to implement 
# iterative segment tree.
def construct_segment_tree(segtree, a, n): 
      
    # assign values to leaves of 
    # the segment tree 
    for i in range(n): 
        segtree[n + i] = a[i]; 
      
    # assign values to remaining nodes 
    # to compute minimum in a given range 
    for i in range(n - 1, 0, -1): 
        segtree[i] = min(segtree[2 * i], 
                         segtree[2 * i + 1]) 
                          
def range_query(segtree, left, right, n):
    left += n 
    right += n
      
    """ Basically the left and right indices 
        will move towards right and left respectively 
        and with every each next higher level and 
        compute the minimum at each height change 
        the index to leaf node first """
    mi = 1e9 # initialize minimum to a very high value
    while (left < right):
        if (left & 1): # if left index in odd 
                mi = min(mi, segtree[left])
                left = left + 1
        if (right & 1): # if right index in odd 
                right -= 1
                mi = min(mi, segtree[right])
                  
        # move to the next higher level
        left = left // 2
        right = right // 2
    return mi
  
def update(segtree, pos, value, n):
      
    # change the index to leaf node first 
    pos += n 
      
    # update the value at the leaf node 
    # at the exact index
    segtree[pos] = value 
    while (pos > 1):
          
        # move up one level at a time in the tree 
        pos >>= 1; 
          
        # update the values in the nodes 
        # in the next higher level
        segtree[pos] = min(segtree[2 * pos], 
                           segtree[2 * pos + 1]) 
  
# Driver Code     
  
# Elements in list
a = [2, 6, 10, 4, 7, 28, 9, 11, 6, 33]
n = len(a) 
  
# Construct the segment tree by assigning
# the values to the internal nodes
segtree = [0 for i in range(2 * n)] 
construct_segment_tree(segtree, a, n);
left = 0
right = 5 #compute minimum in the range left to right
print ("Minimum in range", left, "to", right, "is", 
        range_query(segtree, left, right + 1, n))
  
# update the value of index 3 to 1
index = 3 
value = 1
  
# a[3] = 1;
# Contents of array : {2, 6, 10, 1, 7, 28, 9, 11, 6, 33}
update(segtree, index, value, n); # point update
left = 2
right = 6 # compute minimum in the range left to right
print("Minimum in range", left, "to", right, "is", 
       range_query(segtree, left, right + 1, n))
         
# This code is contributed by sarthak Raghuwanshi


C#
// C# Program to implement iterative segment 
// tree. 
using System;
  
class GFG 
{
  
    static void construct_segment_tree(int[] segtree, 
                                        int[] a, int n)
    {
          
        // assign values to leaves of the segment tree
        for (int i = 0; i < n; i++)
            segtree[n + i] = a[i];
  
        /*
        * assign values to internal nodes
        * to compute minimum in a given range
        */
        for (int i = n - 1; i >= 1; i--)
            segtree[i] = Math.Min(segtree[2 * i], 
                            segtree[2 * i + 1]);
    }
  
    static void update(int[] segtree, int pos, 
                        int value, int n)
    {
  
        // change the index to leaf node first
        pos += n;
  
        // update the value at the leaf node
        // at the exact index
        segtree[pos] = value;
  
        while (pos > 1) 
        {
  
            // move up one level at a time in the tree
            pos >>= 1;
  
            // update the values in the nodes in
            // the next higher level
            segtree[pos] = Math.Min(segtree[2 * pos], 
                                segtree[2 * pos + 1]);
        }
    }
  
    static int range_query(int[] segtree, int left, 
                        int right, int n) 
    {
          
        /*
        * Basically the left and right indices will move
        * towards right and left respectively and with
        * every each next higher level and compute the
        * minimum at each height. */
        // change the index to leaf node first
        left += n;
        right += n;
  
        // initialize minimum to a very high value
        int mi = (int) 1e9;
  
        while (left < right) 
        {
  
            // if left index in odd
            if ((left & 1) == 1)
            {
                mi = Math.Min(mi, segtree[left]);
  
                // make left index even
                left++;
            }
  
            // if right index in odd
            if ((right & 1) == 1) 
            {
  
                // make right index even
                right--;
  
                mi = Math.Min(mi, segtree[right]);
            }
  
            // move to the next higher level
            left /= 2;
            right /= 2;
        }
        return mi;
    }
  
    // Driver Code
    public static void Main(String[] args)
    {
        int[] a = {2, 6, 10, 4, 7, 28, 9, 11, 6, 33};
        int n = a.Length;
  
        /* 
        * Construct the segment tree by assigning
        * the values to the internal nodes
        */
        int[] segtree = new int[2 * n];
        construct_segment_tree(segtree, a, n);
  
        // compute minimum in the range left to right 
        int left = 0, right = 5;
        Console.Write("Minimum in range {0} to {1} is {2}\n", 
                        left, right, range_query(segtree,
                        left, right + 1, n));
  
        // update the value of index 3 to 1 
        int index = 3, value = 1;
          
        // a[3] = 1; 
        // Contents of array : {2, 6, 10, 1, 7, 28, 9, 11, 6, 33}
        update(segtree, index, value, n); // point update
  
        // compute minimum in the range left to right
        left = 2;
        right = 6;
        Console.Write("Minimum in range {0} to {1} is {2}\n", 
                        left, right, range_query(segtree, 
                        left, right + 1, n));
    }
}
  
// This code is contributed by Rajput-Ji


输出:
Minimum in range 0 to 5 is 2
Minimum in range 2 to 6 is 1

时间复杂度: (n log n)
辅助空间: (n)