📌  相关文章
📜  查询以更新找到超过K的第一个数组元素

📅  最后修改于: 2021-04-17 10:19:40             🧑  作者: Mango

给定一个大小为N的数组arr []和一个二维数组Q [] [] ,该数组由以下两种类型的查询组成:

  • 1 XY:Y更新索引X处的数组元素。
  • 2 K:打印第一个数组元素的位置大于或等于K。如果没有这样的索引,则打印-1

例子:

天真的方法:解决此问题的最简单方法如下:

  • 对于类型1的查询,然后将arr [X – 1]更新为Y。
  • 否则,遍历数组并打印第一个数组元素的位置,该位置大于或等于K。

时间复杂度: O(N * | Q |)
辅助空间: O(1)

高效方法:可以通过使用段树来优化上述方法。这个想法是使用带有“节点更新”的“范围最大查询”的概念来构建和更新树。请按照以下步骤解决问题:

  • 用每个节点的最大子树组成一个分段树。
  • 可以通过使用带有节点更新的范围最大查询的概念来执行更新操作
  • 可以通过递归检查以下条件来找到大于或等于K的第一个数组元素的位置:
    • 检查左子树的根是否大于或等于K。如果发现为真,则从左侧子树中找到位置。如果在左子树中未找到此类数组元素,则以递归方式在右子树中找到位置。
    • 否则,以递归方式在右侧子树中找到位置。
  • 最后,打印大于或等于K的数组元素的位置。

下面是上述方法的实现

C++
// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Function to find the mid
// of start and end
int getMid(int s, int e) { return s + (e - s) / 2; }
 
// Function to update nodes at position index
void updateValue(int arr[], int* st, int ss, int se,
                 int index, int value, int node)
{
 
    // If index is out of range
    if (index < ss || index > se) {
        cout << "Invalid Input" << endl;
        return;
    }
 
    // If a leaf node is found
    if (ss == se) {
 
        // update value in array
        arr[index] = value;
 
        // Update value in
        // the segment tree
        st[node] = value;
    }
    else {
 
        // Stores mid of ss and se
        int mid = getMid(ss, se);
 
        // If index is less than or
        // equal to mid
        if (index >= ss && index <= mid) {
 
            // Recursively call for left subtree
            updateValue(arr, st, ss, mid, index, value,
                        2 * node + 1);
        }
        else {
 
            // Recursively call for right subtree
            updateValue(arr, st, mid + 1, se, index, value,
                        2 * node + 2);
        }
 
        // Update st[node]
        st[node] = max(st[2 * node + 1], st[2 * node + 2]);
    }
    return;
}
 
// Function to find the position of first element
// which is greater than or equal to X
int findMinimumIndex(int* st, int ss, int se, int K, int si)
{
 
    // If no such element found in current
    // subtree which is greater than or
    // equal to K
    if (st[si] < K)
        return 1e9;
 
    // If current node is leaf node
    if (ss == se) {
 
        // If value of current node
        // is greater than or equal to X
        if (st[si] >= K) {
 
            return ss;
        }
 
        return 1e9;
    }
 
    // Stores mid of ss and se
    int mid = getMid(ss, se);
 
    int l = 1e9;
 
    // If root of left subtree is
    // greater than or equal to K
    if (st[2 * si + 1] >= K)
        l = min(l, findMinimumIndex(st, ss, mid, K,
                                    2 * si + 1));
 
    // If no such array element is
    // found in the left subtree
    if (l == 1e9 && st[2 * si + 2] >= K)
        l = min(l, findMinimumIndex(st, mid + 1, se, K,
                                    2 * si + 2));
 
    return l;
}
 
// Function to build a segment tree
int Build(int arr[], int ss, int se, int* st, int si)
{
 
    // If current node is leaf node
    if (ss == se) {
        st[si] = arr[ss];
        return arr[ss];
    }
 
    // store mid of ss and se
    int mid = getMid(ss, se);
 
    // Stores maximum of left subtree and rightsubtree
    st[si] = max(Build(arr, ss, mid, st, si * 2 + 1),
                 Build(arr, mid + 1, se, st, si * 2 + 2));
 
    return st[si];
}
 
// Function to initialize a segment tree
// for the given array
int* constructST(int arr[], int n)
{
 
    // Height of segment tree
    int x = (int)(ceil(log2(n)));
 
    // Maximum size of segment tree
    int max_size = 2 * (int)pow(2, x) - 1;
 
    // Allocate memory
    int* st = new int[max_size];
 
    // Fill the allocated memory st
    Build(arr, 0, n - 1, st, 0);
 
    // Return the constructed segment tree
    return st;
}
 
// Function to perform the queries of
// the given type
void PerformQueries(int arr[], int N,
                    vector > Q)
{
 
    // Build segment tree for the given array
    int* st = constructST(arr, N);
 
    // Traverse the query array
    for (int i = 0; i < Q.size(); i++) {
 
        // If query of type 1 found
        if (Q[i][0] == 1)
 
            updateValue(arr, st, 0, N - 1, Q[i][1] - 1, 5,
                        0);
        else {
 
            // Stores index of first array element
            // which is greater than or equal
            // to Q[i][1]
            int f = findMinimumIndex(st, 0, N - 1, Q[i][1],
                                     0);
            if (f < N)
                cout << f + 1 << " ";
            else
                cout << -1 << " ";
        }
    }
}
 
// Driver Code
int main()
{
    int arr[] = { 1, 3, 2, 4, 6 };
 
    vector > Q{
        { 2, 5 }, { 1, 3, 5 }, { 2, 4 }, { 2, 8 }
    };
    int N = sizeof(arr) / sizeof(arr[0]);
 
    PerformQueries(arr, N, Q);
    return 0;
}


Java
// Java program to implement
// the above approach
 
import java.io.*;
class GFG
{
 
  // Function to find the mid
  // of start and end
  static int getMid(int s, int e)
  {
    return s + (e - s) / 2;
  }
  static void updateValue(int arr[], int[] st, int ss,
                          int se, int index, int value,
                          int node)
  {
 
    // If index is out of range
    if (index < ss || index > se)
    {
      System.out.println("Invalid Input");
      return;
    }
 
    // If a leaf node is found
    if (ss == se)
    {
 
      // update value in array
      arr[index] = value;
 
      // Update value in
      // the segment tree
      st[node] = value;
    }
    else
    {
 
      // Stores mid of ss and se
      int mid = getMid(ss, se);
 
      // If index is less than or
      // equal to mid
      if (index >= ss && index <= mid)
      {
 
        // Recursively call for left subtree
        updateValue(arr, st, ss, mid, index, value,
                    2 * node + 1);
      }
      else
      {
 
        // Recursively call for right subtree
        updateValue(arr, st, mid + 1, se, index,
                    value, 2 * node + 2);
      }
 
      // Update st[node]
      st[node] = Math.max(st[2 * node + 1],
                          st[2 * node + 2]);
    }
  }
 
  // Function to find the position of first element
  // which is greater than or equal to X
  static int findMinimumIndex(int[] st, int ss, int se,
                              int K, int si)
  {
 
    // If no such element found in current
    // subtree which is greater than or
    // equal to K
    if (st[si] < K)
      return 1000000000;
 
    // If current node is leaf node
    if (ss == se)
    {
 
      // If value of current node
      // is greater than or equal to X
      if (st[si] >= K)
      {
        return ss;
      }
      return 1000000000;
    }
 
    // Stores mid of ss and se
    int mid = getMid(ss, se);
 
    int l = 1000000000;
 
    // If root of left subtree is
    // greater than or equal to K
    if (st[2 * si + 1] >= K)
      l = Math.min(l, findMinimumIndex(st, ss, mid, K,
                                       2 * si + 1));
 
    // If no such array element is
    // found in the left subtree
    if (l == 1e9 && st[2 * si + 2] >= K)
      l = Math.min(l,
                   findMinimumIndex(st, mid + 1, se,
                                    K, 2 * si + 2));
 
    return l;
  }
 
  // Function to build a segment tree
  static int Build(int arr[], int ss, int se, int[] st,
                   int si)
  {
 
    // If current node is leaf node
    if (ss == se)
    {
      st[si] = arr[ss];
      return arr[ss];
    }
 
    // store mid of ss and se
    int mid = getMid(ss, se);
 
    // Stores maximum of left subtree and rightsubtree
    st[si] = Math.max(
      Build(arr, ss, mid, st, si * 2 + 1),
      Build(arr, mid + 1, se, st, si * 2 + 2));
 
    return st[si];
  }
 
  // Function to initialize a segment tree
  // for the given array
  static int[] constructST(int arr[], int n)
  {
 
    // Height of segment tree
    int x = (int)Math.ceil(Math.log(n) / Math.log(2));
 
    // Maximum size of segment tree
    int max_size = 2 * (int)Math.pow(2, x) - 1;
 
    // Allocate memory
    int[] st = new int[max_size];
 
    // Fill the allocated memory st
    Build(arr, 0, n - 1, st, 0);
 
    // Return the constructed segment tree
    return st;
  }
  static void PerformQueries(int arr[], int N, int[][] Q)
  {
 
    // Build segment tree for the given array
    int[] st = constructST(arr, N);
 
    // Traverse the query array
    for (int i = 0; i < Q.length; i++)
    {
 
      // If query of type 1 found
      if (Q[i][0] == 1)
        updateValue(arr, st, 0, N - 1, Q[i][1] - 1,
                    5, 0);
      else {
 
        // Stores index of first array element
        // which is greater than or equal
        // to Q[i][1]
        int f = findMinimumIndex(st, 0, N - 1,
                                 Q[i][1], 0);
        if (f < N)
          System.out.print(f + 1 + " ");
        else
          System.out.print(-1 + " ");
      }
    }
  }
 
  // Driver Code
  public static void main(String[] args)
  {
    int arr[] = { 1, 3, 2, 4, 6 };
     
    int[][] Q
      = { { 2, 5 }, { 1, 3, 5 }, { 2, 4 }, { 2, 8 } };
    int N = arr.length;
    PerformQueries(arr, N, Q);
  }
}
 
// This code is contributed by hemanthsawarna1506


C#
// C# program to implement
// the above approach
using System;
 
class GFG{
 
// Function to find the mid
// of start and end
static int getMid(int s, int e)
{
    return s + (e - s) / 2;
}
 
static void updateValue(int[] arr, int[] st, int ss,
                        int se, int index, int value,
                        int node)
{
     
    // If index is out of range
    if (index < ss || index > se)
    {
        Console.WriteLine("Invalid Input");
        return;
    }
 
    // If a leaf node is found
    if (ss == se)
    {
         
        // Update value in array
        arr[index] = value;
 
        // Update value in
        // the segment tree
        st[node] = value;
    }
    else
    {
         
        // Stores mid of ss and se
        int mid = getMid(ss, se);
 
        // If index is less than or
        // equal to mid
        if (index >= ss && index <= mid)
        {
             
            // Recursively call for left subtree
            updateValue(arr, st, ss, mid, index, value,
                        2 * node + 1);
        }
        else
        {
             
            // Recursively call for right subtree
            updateValue(arr, st, mid + 1, se, index,
                        value, 2 * node + 2);
        }
 
        // Update st[node]
        st[node] = Math.Max(st[2 * node + 1],
                            st[2 * node + 2]);
    }
}
 
// Function to find the position of first element
// which is greater than or equal to X
static int findMinimumIndex(int[] st, int ss, int se,
                            int K, int si)
{
     
    // If no such element found in current
    // subtree which is greater than or
    // equal to K
    if (st[si] < K)
        return 1000000000;
 
    // If current node is leaf node
    if (ss == se)
    {
         
        // If value of current node
        // is greater than or equal to X
        if (st[si] >= K)
        {
            return ss;
        }
        return 1000000000;
    }
 
    // Stores mid of ss and se
    int mid = getMid(ss, se);
 
    int l = 1000000000;
 
    // If root of left subtree is
    // greater than or equal to K
    if (st[2 * si + 1] >= K)
        l = Math.Min(l, findMinimumIndex(st, ss, mid, K,
                                         2 * si + 1));
 
    // If no such array element is
    // found in the left subtree
    if (l == 1e9 && st[2 * si + 2] >= K)
        l = Math.Min(l,
                     findMinimumIndex(st, mid + 1, se,
                                    K, 2 * si + 2));
 
    return l;
}
 
// Function to build a segment tree
static int Build(int[] arr, int ss, int se,
                 int[] st, int si)
{
     
    // If current node is leaf node
    if (ss == se)
    {
        st[si] = arr[ss];
        return arr[ss];
    }
 
    // Store mid of ss and se
    int mid = getMid(ss, se);
 
    // Stores maximum of left subtree and rightsubtree
    st[si] = Math.Max(
        Build(arr, ss, mid, st, si * 2 + 1),
        Build(arr, mid + 1, se, st, si * 2 + 2));
 
    return st[si];
}
 
// Function to initialize a segment tree
// for the given array
static int[] constructST(int[] arr, int n)
{
     
    // Height of segment tree
    int x = (int)Math.Ceiling(Math.Log(n) /
                              Math.Log(2));
 
    // Maximum size of segment tree
    int max_size = 2 * (int)Math.Pow(2, x) - 1;
 
    // Allocate memory
    int[] st = new int[max_size];
 
    // Fill the allocated memory st
    Build(arr, 0, n - 1, st, 0);
 
    // Return the constructed segment tree
    return st;
}
 
static void PerformQueries(int[] arr, int N, int[][] Q)
{
     
    // Build segment tree for the given array
    int[] st = constructST(arr, N);
 
    // Traverse the query array
    for(int i = 0; i < Q.Length; i++)
    {
         
        // If query of type 1 found
        if (Q[i][0] == 1)
            updateValue(arr, st, 0, N - 1,
                        Q[i][1] - 1, 5, 0);
        else
        {
             
            // Stores index of first array element
            // which is greater than or equal
            // to Q[i][1]
            int f = findMinimumIndex(st, 0, N - 1,
                                     Q[i][1], 0);
            if (f < N)
                Console.Write(f + 1 + " ");
            else
                Console.Write(-1 + " ");
        }
    }
}
 
// Driver Code
public static void Main(string[] args)
{
    int[] arr = { 1, 3, 2, 4, 6 };
    int[][] Q = new int[4][];
 
    // Initialize the elements
    Q[0] = new int[] { 2, 5 };
    Q[1] = new int[] { 1, 3, 5 };
    Q[2] = new int[] { 2, 4 };
    Q[3] = new int[] { 2, 8 };
 
    int N = arr.Length;
    PerformQueries(arr, N, Q);
}
}
 
// This code is contributed by ukasp


输出:

5 3 -1