线段树 | 区间最小值查询

我们在前一篇文章中,通过一个简单的例子介绍了线段树。在这篇文章中,我们将讨论<a href="https://en.wikipedia.org/wiki/RangeMinimumQuery">区间最小值查询问题,这是线段树应用的另一个典型案例。以下是问题的具体陈述:

我们有一个数组 arr[0 . . . n-1]。我们需要能够高效地找到从索引 qs(查询起始)到 qe (查询结束)之间的最小值,其中 0 <= qs <= qe <= n-1

一种简单的方法是运行一个从 qs qe 的循环,以找到给定范围内的最小元素。在最坏的情况下,这种解法需要 O(n) 的时间。
另一种解法是创建一个二维数组,其中条目 INLINECODE72ff28d1 存储范围 INLINECODE2a30c3cc 内的最小值。现在可以在 O(1) 时间内计算给定范围的最小值,但预处理需要 O(n2) 时间。此外,这种方法需要 O(n2) 的额外空间,对于大型输入数组来说,这可能会变得非常巨大。
线段树可以在适度的时间内进行预处理和查询。使用线段树,预处理时间为 O(n),而范围最小值查询的时间复杂度为 O(log n)。所需的额外空间为 O(n),用于存储线段树。

线段树的表示

> 1. 叶子节点是输入数组的元素。

> 2. 每个内部节点代表其所有子叶子节点的最小值。

我们使用树的数组表示法来表示线段树。对于索引 INLINECODE47c61bb9 处的每个节点,左子节点位于索引 INLINECODE03a3c0e8,右子节点位于 (2 * i + 2),父节点位于 (i – 1) / 2

!线段树区间最小值查询示意图

从给定数组构造线段树

> 我们从数组段 arr[0 . . . n-1] 开始。每次我们将当前段分成两半(如果它还没有成为长度为 1 的段),然后对两半都调用相同的过程,对于每个这样的段,我们将最小值存储在一个线段树节点中。

构造的线段树的所有层都将被完全填充,除了最后一层。此外,该树将是一棵<a href="https://en.wikipedia.org/wiki/Binarytree#Typesofbinarytrees">满二叉树,因为我们总是在每一层将段分成两半。由于构造的树始终是具有 n 个叶子的满二叉树,因此将有 n – 1 个内部节点。所以节点总数将是 2 * n – 1。

线段树的高度将是 ?log?n?。由于树是使用数组表示的,并且必须维护父索引和子索引之间的关系,因此为线段树分配的内存大小将是 2 2?log2n? – 1*。

查询给定范围的最小值

> 一旦树被构造完成,如何使用构造好的线段树进行范围最小值查询?以下是获取最小值的算法。

>

> // qs–> 查询起始索引, qe –> 查询结束索引

> int RMQ(node, qs, qe) {

> if 节点的范围完全在 qs 和 qe 之内

> return 节点中的值

> else if 节点的范围完全在 qs和 qe 之外

> return INFINITE (无限大)

> else

> return min ( RMQ(节点的左孩子, qs, qe), RMQ (节点的右孩子, qs, qe) )

> }

C++

`

// C++ program for range minimum
// query using segment tree 
#include 
using namespace std;

// A utility function to get minimum of two numbers 
int minVal(int x, int y) { 
    return (x  Pointer to segment tree 
// index --> Index of current node in the tree
// ss & se --> Starting and ending indexes 
// qs & qe --> Starting and ending indexes of query range
int RMQUtil(vector &st, int ss, int se, int qs, 
                                int qe, int index) { 

    // If segment of this node is a part of given range
    // then return the min of the segment
    if (qs = se) 
        return st[index]; 

    // If segment of this node if outside the range
    if (se  qe) 
        return INT_MAX; 

    // If a part of this segment
    // overlaps with the given range 
    int mid = getMid(ss, se); 
    return minVal(RMQUtil(st, ss, mid, qs, qe, 2*index+1), 
                RMQUtil(st, mid+1, se, qs, qe, 2*index+2)); 
} 

// Return minimum of elements in range
// from index qs to qe
int RMQ(vector &st, int n, int qs, int qe) { 

    // Check for invalid input
    if (qs  n-1 || qs > qe) { 
        cout << "Invalid Input"; 
        return -1; 
    } 

    return RMQUtil(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(vector &arr, int ss, int se, 
                    vector &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 minimum of two values in this node
    int mid = getMid(ss, se); 
    st[si] = minVal(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 */
vector constructST(vector &arr, int n) { 
    // Allocate memory for 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; 

    vector st(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() { 
    vector arr = {1, 3, 2, 7, 9, 11}; 
    int n = arr.size(); 

    // Build segment tree from given array 
    vector st = constructST(arr, n); 

    int qs = 1;  // Starting index of query range 
    int qe = 5;  // Ending index of query range 

    // Print minimum value in arr[qs..qe] 
    cout << "Minimum of values in range [" << qs << ", " << qe 
         << "] is = " << RMQ(st, n, qs, qe) << endl; 

    return 0; 
}
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。如需转载,请注明文章出处豆丁博客和来源网址。https://shluqu.cn/44622.html
点赞
0.00 平均评分 (0% 分数) - 0