📌  相关文章
📜  使用段树查询给定索引范围内最大对和

📅  最后修改于: 2021-05-17 05:53:07             🧑  作者: Mango

给定包含N个整数的数组arr []和表示范围[L,R]的数组Q [] ,任务是找到范围[L,R]中的最大对和值,其中0≤L≤R≤N – 1。

例子:

幼稚的方法:针对此问题的幼稚的方法是从[L,R]运行循环并找到给定范围内的两个最大元素。它们的总和始终是给定索引范围内的最大对总和。对于每个查询,此方法的时间复杂度为O(N)。

高效的方法:想法是使用段树来执行一些预处理并在对数时间内找到每个查询的值。

细分树的表示形式:

  1. 叶节点是输入数组的元素。
  2. 每个内部节点包含最大对和以及其下所有叶子的最大元素。

树的数组表示形式用于表示段树。对于索引’i’上的每个节点,左子节点在索引((2 * i)+1) ,右子节点在索引((2 * i)+ 2) ,而父节点在索引(( (i – 1)/ 2)

从给定数组构造细分树:

  • 我们从给定数组arr []的一段开始。
  • 在每一步中,我们将当前片段分为两半(如果尚未变成长度为1的片段)。
  • 对数组的所获得的两半再次递归执行上述步骤。
  • 对于每个段,我们将最大值和最大对和存储在段树节点中。
  • 每个节点的最大对和和最大值可以找到:

下面是上述方法的实现:

// 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是数组的大小。