给定数组arr [0。 。 。 n-1]。我们需要有效地找到从索引qs(查询开始)到qe(查询结束)的最小值和最大值,其中0 <= qs <= qe <= n-1。我们有多个查询。
例子:
Input : arr[] = {1, 8, 5, 9, 6, 14, 2, 4, 3, 7}
queries = 5
qs = 0 qe = 4
qs = 3 qe = 7
qs = 1 qe = 6
qs = 2 qe = 5
qs = 0 qe = 8
Output: Minimum = 1 and Maximum = 9
Minimum = 2 and Maximum = 14
Minimum = 2 and Maximum = 14
Minimum = 5 and Maximum = 14
Minimum = 1 and Maximum = 14
简单的解决方案:我们使用锦标赛方法为每个查询解决此问题。此方法的复杂度将为O(查询* n)。
高效的解决方案:使用细分树可以更有效地解决此问题。首先阅读给定的段树链接,然后开始解决此问题。
// C++ program to find minimum and maximum using segment tree
#include
using namespace std;
// Node for storing minimum nd maximum value of given range
struct node
{
int minimum;
int maximum;
};
// 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 minimum and maximum value in
a given range of array indexes. The following are parameters
for this function.
st --> Pointer to segment tree
index --> 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[index]
qs & qe --> Starting and ending indexes of query range */
struct node MaxMinUntill(struct node *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 minimum and maximum node of the segment
struct node tmp,left,right;
if (qs <= ss && qe >= se)
return st[index];
// If segment of this node is outside the given range
if (se < qs || ss > qe)
{
tmp.minimum = INT_MAX;
tmp.maximum = INT_MIN;
return tmp;
}
// If a part of this segment overlaps with the given range
int mid = getMid(ss, se);
left = MaxMinUntill(st, ss, mid, qs, qe, 2*index+1);
right = MaxMinUntill(st, mid+1, se, qs, qe, 2*index+2);
tmp.minimum = min(left.minimum, right.minimum);
tmp.maximum = max(left.maximum, right.maximum);
return tmp;
}
// Return minimum and maximum of elements in range from index
// qs (quey start) to qe (query end). It mainly uses
// MaxMinUtill()
struct node MaxMin(struct node *st, int n, int qs, int qe)
{
struct node tmp;
// Check for erroneous input values
if (qs < 0 || qe > n-1 || qs > qe)
{
printf("Invalid Input");
tmp.minimum = INT_MIN;
tmp.minimum = INT_MAX;
return tmp;
}
return MaxMinUntill(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
void constructSTUtil(int arr[], int ss, int se, struct node *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].minimum = arr[ss];
st[si].maximum = arr[ss];
return ;
}
// If there are more than one elements, then recur for left and
// right subtrees and store the minimum and maximum of two values
// in this node
int mid = getMid(ss, se);
constructSTUtil(arr, ss, mid, st, si*2+1);
constructSTUtil(arr, mid+1, se, st, si*2+2);
st[si].minimum = min(st[si*2+1].minimum, st[si*2+2].minimum);
st[si].maximum = max(st[si*2+1].maximum, st[si*2+2].maximum);
}
/* Function to construct segment tree from given array. This function
allocates memory for segment tree and calls constructSTUtil() to
fill the allocated memory */
struct node *constructST(int 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;
struct node *st = new struct node[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, 8, 5, 9, 6, 14, 2, 4, 3, 7};
int n = sizeof(arr)/sizeof(arr[0]);
// Build segment tree from given array
struct node *st = constructST(arr, n);
int qs = 0; // Starting index of query range
int qe = 8; // Ending index of query range
struct node result=MaxMin(st, n, qs, qe);
// Print minimum and maximum value in arr[qs..qe]
printf("Minimum = %d and Maximum = %d ",
result.minimum, result.maximum);
return 0;
}
输出:
Minimum = 1 and Maximum = 14
时间复杂度: O(查询*登录)
如果阵列上没有更新,我们可以做得更好吗?
上述基于分段树的解决方案还允许在O(Log n)时间内进行数组更新。假设没有更新(或数组是静态的)的情况。实际上,我们可以通过一些预处理处理O(1)时间中的所有查询。一种简单的解决方案是制作一个二维表节点,该表存储所有范围的最小值和最大值。该解决方案需要O(1)查询时间,但需要O(n 2 )预处理时间和O(n 2 )额外空间,这对于大n来说可能是个问题。我们可以使用稀疏表在O(1)查询时间,O(n Log n)空间和O(n Log n)预处理时间中解决此问题。