📌  相关文章
📜  查找第k个最小元素并进行点更新的查询:C++中的有序集

📅  最后修改于: 2021-04-17 12:34:20             🧑  作者: Mango

给定大小为N的数组arr []和包含M个查询的集合Q [] [],任务是在给定数组上执行查询,以便可以有两种类型的查询:

  • 类型1: [i,x] –将i个索引处的元素更新为x。
  • 类型2: [k] –在数组中找到第k个最小的元素。

例子:

幼稚的方法:针对此问题的幼稚的方法是在恒定时间内更新数组中的第i个元素,并使用排序找到第K最小的元素。

时间复杂度: O(M *(N * log(N)))其中,M是查询数,N是数组的大小。

高效方法:想法是使用类似于集合的基于策略的数据结构。

此处,基于树的容器用于以排序树的形式存储数组,以使左侧的所有节点都小于根,而右侧的所有节点都大于根。以下是数据结构的属性:

  • 通过保持节点不变来建立索引,其中每个节点在其子树中都包含一个节点数。
  • 每次插入一个新节点或删除一个节点时,我们都可以冒泡到根,从而保持O(logN)时间的不变性。
  • 因此,节点在其左子树中的计数按排序顺序给出了该节点的索引,因为左子树中每个节点的值都小于父节点。

因此,我们的想法是对每个查询采用以下方法:

  1. 类型1:对于此查询,我们更新数组的第i个元素。因此,我们需要更新数组和数据结构中的元素。为了更新树容器中的值,在树中找到值arr [i],将其从树中删除,然后将更新后的值重新插入树中。
  2. 类型2:为了找到第K最小元素,在树上使用find_by_order(K – 1),因为数据是排序数据。这类似于对排序数组执行二进制搜索操作。

下面是上述方法的实现:

// C++ implementation of the above approach
  
#include 
#include 
#include 
using namespace std;
using namespace __gnu_pbds;
  
// Defining the policy based Data Structure
typedef tree,
             null_type,
             less >,
             rb_tree_tag,
             tree_order_statistics_node_update>
    indexed_set;
  
// Elements in the array are not unique,
// so a pair is used to give uniqueness
// by incrementing cnt and assigning
// with array elements to insert in mySet
int cnt = 0;
  
// Variable to store the data in the
// policy based Data Structure
indexed_set mySet;
  
// Function to insert the elements
// of the array in mySet
void insert(int n, int arr[])
{
    for (int i = 0; i < n; i++) {
        mySet.insert({ arr[i], cnt });
        cnt++;
    }
}
  
// Function to update the value in
// the data structure
void update(int x, int y)
{
    // Get the pointer of the element
    // in mySet which has to be updated
    auto it = mySet.lower_bound({ y, 0 });
  
    // Delete from mySet
    mySet.erase(it);
  
    // Insert the updated value in mySet
    mySet.insert({ x, cnt });
    cnt++;
}
  
// Function to find the K-th smallest
// element in the set
int get(int k)
{
    // Find the pointer to the kth smallest element
    auto it = mySet.find_by_order(k - 1);
    return (it->first);
}
  
// Function to perform the queries on the set
void operations(int arr[], int n,
                vector > query, int m)
{
    // To insert the element in mySet
    insert(n, arr);
  
    // Iterating through the queries
    for (int i = 0; i < m; i++) {
  
        // Checking if the query is of type 1
        // or type 2
        if (query[i][0] == 1) {
  
            // The array is 0-indexed
            int j = query[i][1] - 1;
            int x = query[i][2];
  
            // Update the element in mySet
            update(x, arr[j]);
  
            // Update the element in the array
            arr[j] = x;
        }
        else {
            int K = query[i][1];
  
            // Print Kth smallest element
            cout << get(K) << endl;
        }
    }
}
  
// Driver code
int main()
{
    int n = 5, m = 6, arr[] = { 1, 0, 4, 2, 0 };
  
    vector > query = { { 1, 2, 1 },
                                   { 2, 2 },
                                   { 1, 4, 5 },
                                   { 1, 3, 7 },
                                   { 2, 1 },
                                   { 2, 5 } };
  
    operations(arr, n, query, m);
  
    return 0;
}
输出:
1
0
7

时间复杂度:由于每个操作都需要O(Log(N))时间,并且有M个查询,因此总体时间复杂度为O(M * Log(N))