给定一个包含N 个整数的数组 arr[]和一个表示范围[L, R]的数组 Q[] ,任务是找到范围 [L, R]中的最大对和值,其中 0 ≤ L ≤ R ≤ N – 1。
例子:
Input: arr[] = {1, 3, 2, 7, 9, 11}, Q[] = {1, 4}
Output: 16
Explanation:
The greatest pair sum in range 1 to 4 is 7 + 9 = 16.
Input: arr[] = {0, 1, 2, 3, 4, 5, 6, 7}, Q[] = {5, 7}
Output: 13
Explanation:
The greatest pair sum in range 5 to 7 is 6 + 7 = 13.
朴素的方法:这个问题的朴素的方法是从 [L, R] 运行一个循环并找到给定范围内的两个最大元素。它们的总和始终是给定索引范围内的最大对总和。对于每个查询,这种方法的时间复杂度是O(N)。
高效的方法:这个想法是使用一个段树来执行一些预处理并在对数时间内找到每个查询的值。
Segment 树的表示:
- 叶节点是输入数组的元素。
- 每个内部节点包含最大的对和以及其下所有叶子的最大元素。
树的数组表示用于表示段树。为索引的“i”在每个节点,左子是在指数((2 * I)+ 1),右子是索引处((2 * I)+ 2)和父是索引处( (i – 1)/2) 。
从给定数组构建段树:
- 我们从给定数组 arr[] 中的一个段开始。
- 在每一步,我们将当前段分成两半(如果它还没有成为长度为 1 的段)。
- 对获得的数组的一半再次递归执行上述步骤。
- 对于每个段,我们在段树节点中存储最大值以及最大对和。
- 可以找到每个节点的最大对和和最大值:
Maximum Pair Sum-> maximum( Left child’s maximum pair sum, Right child’s maximum pair sum, Left child’s maximum value + Right child’s maximum value)
Maximum Value -> maximum(Left child’s maximum value, Right child’s maximum value )
下面是上述方法的实现:
// C++ program for range greatest
// pair sum query using segment tree
#include
using namespace std;
// Defining the node
struct node {
int maxVal, greatestPSum;
} st[100009];
// A utility function
node util(node x, node y)
{
node ans;
// Find the maximum pair sum
ans.greatestPSum
= max(x.maxVal + y.maxVal,
max(x.greatestPSum,
y.greatestPSum));
// Find the maximum value
ans.maxVal = max(x.maxVal, y.maxVal);
return ans;
}
// 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
greatest pair sum value in a given range
of array indexes. Here:
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 */
node query(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 <= ss && qe >= se)
return st[index];
node temp;
temp.maxVal = -1,
temp.greatestPSum = -1;
// If segment of this node
// is outside the given range
if (se < qs || ss > qe)
return temp;
// If a part of this segment
// overlaps with the given range
int mid = getMid(ss, se);
return util(query(ss, mid, qs,
qe, 2 * index + 1),
query(mid + 1, se, qs,
qe, 2 * index + 2));
}
// Function to return the greatest pair
// sum in the range from index
// qs (query start) to qe (query end)
node checkQuery(int n, int qs, int qe)
{
node temp;
temp.maxVal = -1, temp.greatestPSum = -1;
// Check for erroneous input values
if (qs < 0 || qe > n - 1 || qs > qe) {
cout << "Invalid Input";
return temp;
}
return query(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
node constructST(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].maxVal = arr[ss];
st[si].greatestPSum = 0;
return st[si];
}
// If there are more than one elements,
// then recur for left and right subtrees
int mid = getMid(ss, se);
st[si] = util(constructST(arr, ss, mid,
si * 2 + 1),
constructST(arr, mid + 1, se,
si * 2 + 2));
return st[si];
}
// Utility function to find the
// greatest pair sum for the given
// queries
void operation(int arr[], int n,
int qs, int qe)
{
// Build segment tree from given array
constructST(arr, 0, n - 1, 0);
node ans = checkQuery(n, qs, qe);
// Print minimum value in arr[qs..qe]
cout << ans.greatestPSum << endl;
}
// Driver code
int main()
{
int arr[] = { 1, 3, 2, 7, 9, 11 };
int n = sizeof(arr) / sizeof(arr[0]);
int L = 1;
int R = 4;
operation(arr, n, L, R);
return 0;
}
16
时间复杂度:
- 树构造的时间复杂度为O(N) ,其中 N 是数组的大小。
- 每个查询的时间复杂度为O(log(N)) ,其中 N 是数组的大小。
如果您想与行业专家一起参加直播课程,请参阅Geeks Classes Live