Выполнять запросы на добавление, обновление, удаление и ранжирование суммы в заданном массиве
Дан массив arr [] размера N, и задача состоит в том, чтобы ответить на Q запросов следующих типов:
- 1 X 0: добавить X в конец массива.
- 2 XY: установите arr [X] = Y.
- 3 X 0: удалить arr [X] .
- 4 XY: Найдите сумму в диапазоне [X, Y] .
Обратите внимание, что после удаления arr [X] в типе запроса 3 все элементы после индекса X будут сдвинуты влево на одну позицию.
Примеры:
Input: arr[] = {1, 2, 5, 3, 4}, Q[][] = {
{4, 2, 4},
{3, 3, 0},
{1, 6, 0},
{4, 3, 5}}
Output:
10
13
First Query -> sum(arr[1], arr[2], arr[3])
Second Query -> arr[] = { 1, 2, 3, 4 }
Third Query -> arr[] = { 1, 2, 3, 4, 6 }
Fourth Query -> sum(arr[2], arr[3], arr[4])
Input: arr[] = {1, 2, 3, 4, 5}, Q[][] = {
{4, 1, 5},
{3, 3, 0},
{1, 6, 0},
{4, 3, 5},
{2, 4, 10}.
{4, 1, 5}}
Output:
15
15
23
Наивный подход: наивный способ решить эту проблему - выполнить запросы непосредственно к заданному массиву, который будет иметь временную сложность O (Q * N) .
Эффективный подход:
- Поскольку есть некоторые структуры данных, такие как дерево сегментов или BIT (дерево Фенвика), которые обеспечивают обновление точки и сумму диапазона в O (logN) для каждого запроса.
- Там пост использует дерево Фенвика, чтобы сделать то же самое, поэтому настоятельно рекомендуется пройти обновление точки в Дереве Фенвика.
- Но основная проблема заключается в выполнении операции удаления ( запросы типа 3 ), после выполнения требуется сдвиг, который снова приведет к O (Q * N) в худшем случае.
- Можно использовать уловку, заключающуюся в том, что после удаления элемента просто обновите значение в A [X] = 0 и сопоставьте индекс после X с X + количество элементов, удаленных до X.
- Чтобы найти количество элементов, удаленных до X , будет использоваться другое дерево Фенвика (как idx в реализации) и продолжать добавлять 1 в том индексе, где выполняется операция удаления.
- Означает, что во время выборки или получения определенного индекса можно сделать запрос к дереву idx и обновить индекс X до X + sum (X, idx) .
Below is the implementation of the above approach:
C++
// C++ implementation of the approach#include <bits/stdc++.h>using namespace std;// Size of the array (MAX)const int N = 2e5 + 10;// To store the sum of// the array elementsvector<int> bit(N, 0);// To keep track of how many type 3// queries have been performed before// a particular indexvector<int> idx(N, 0);// Function to perform the point// update in Fenwick treevoid update(int idx, int val, vector<int>& bitt){ while (idx < N) { bitt[idx] += val; idx += idx & (-idx); }}// Function to return the sum// of the elements A[1...idx]// from BITint sum(int idx, vector<int>& bitt){ int res = 0; while (idx > 0) { res += bitt[idx]; idx -= idx & (-idx); } return res;}// Function to perform the queries and// return the answer vectorvector<int> peformQueries(vector<int>& A, vector<vector<int> >& B){ // For 1 bases indexing // insert 0 in the vector A.insert(A.begin(), 0); // Updated size of the vector int n = (int)A.size(); // Updating the bit tree for (int i = 1; i < n; ++i) { update(i, A[i], bit); } // Vector to store the answers // of range sum vector<int> ans; // Iterating in the query // vector for (auto i : B) { int type = i[0]; int x = i[1], v = i[2]; // If the query is of // type 1 if (type == 1) { // Updating the tree // with x in the last update(n, x, bit); // Pushing back the value // in the original vector A.push_back(x); // Incrementing the size // of the vector by 1 n++; } // If the query is of type 2 else if (type == 2) { // Getting the updated index // in case of any query of // type 3 occured before it int id = x + sum(x, idx); // Making the effect to that // value to 0 by subtracting // same value from the tree update(id, -A[id], bit); // Updating the A[id] to v A[id] = v; // Now update the // bit by v at x update(id, v, bit); } // If the query is of type 3 else if (type == 3) { // Get the current index int id = x + sum(x, idx); // Remove the effect of that // index from the bit tree update(id, -A[id], bit); // Update the idx tree // because one element has // been deleted update(x, 1, idx); // Update the idx val to 0 A[id] = 0; } // If the query is of type 4 else { // Get the updated range int xx = x + sum(x, idx); int vv = v + sum(v, idx); // Push_back the value ans.push_back(sum(vv, bit) - sum(xx - 1, bit)); } } return ans;}// Driver codeint main(){ vector<int> A = { 1, 2, 5, 3, 4 }; // Queries vector<vector<int> > B = { { 4, 2, 4 }, { 3, 3, 0 }, { 1, 6, 0 }, { 4, 3, 5 }, }; // Get the answer array vector<int> ans = peformQueries(A, B); // printing the answer for (int i : ans) cout << i << "
"; return 0;} |
Java
// Java implementation of the approachimport java.util.*;class GFG { // Size of the array (MAX) static int N = (int) 2e5 + 10; // To store the sum of // the array elements static int[] bit = new int[N]; // To keep track of how many type 3 // queries have been performed before // a particular index static int[] idx = new int[N]; // Function to perform the point // update in Fenwick tree static void update(int idx, int val, int[] bitt) { while (idx < N) { bitt[idx] += val; idx += idx & (-idx); } } // Function to return the sum // of the elements A[1...idx] // from BIT static int sum(int idx, int[] bitt) { int res = 0; while (idx > 0) { res += bitt[idx]; idx -= idx & (-idx); } return res; } // Function to perform the queries and // return the answer vector static Vector<Integer> peformQueries(Vector<Integer> A, int[][] B) { // For 1 bases indexing // insert 0 in the vector A.insertElementAt(0, 0); // Updated size of the vector int n = (int) A.size(); // Updating the bit tree for (int i = 1; i < n; ++i) { update(i, A.elementAt(i), bit); } // Vector to store the answers // of range sum Vector<Integer> ans = new Vector<>(); // Iterating in the query // vector for (int[] i : B) { int type = i[0]; int x = i[1], v = i[2]; // If the query is of // type 1 if (type == 1) { // Updating the tree // with x in the last update(n, x, bit); // Pushing back the value // in the original vector A.add(x); // Incrementing the size // of the vector by 1 n++; } // If the query is of type 2 else if (type == 2) { // Getting the updated index // in case of any query of // type 3 occured before it int id = x + sum(x, idx); // Making the effect to that // value to 0 by subtracting // same value from the tree update(id, -A.elementAt(id), bit); // Updating the A[id] to v A.set(id, v); // Now update the // bit by v at x update(id, v, bit); } // If the query is of type 3 else if (type == 3) { // Get the current index int id = x + sum(x, idx); // Remove the effect of that // index from the bit tree update(id, -A.elementAt(id), bit); // Update the idx tree // because one element has // been deleted update(x, 1, idx); // Update the idx val to 0 A.set(id, 0); } // If the query is of type 4 else { // Get the updated range int xx = x + sum(x, idx); int vv = v + sum(v, idx); // Push_back the value ans.add(sum(vv, bit) - sum(xx - 1, bit)); } } return ans; } // Driver Code public static void main(String[] args) { Integer[] a = { 1, 2, 5, 3, 4 }; Vector<Integer> A = new Vector<Integer>(Arrays.asList(a)); // Queries int[][] B = { { 4, 2, 4 }, { 3, 3, 0 }, { 1, 6, 0 }, { 4, 3, 5 } }; // Get the answer array Vector<Integer> ans = peformQueries(A, B); // printing the answer for (int i : ans) System.out.println(i); }}// This code is contributed by// sanjeev2552 |
Python3
# Python implementation of the approach# Size of the array (MAX)N = int(2e5) + 10# To store the sum of# the array elementsbit = [0] * N# To keep track of how many type 3# queries have been performed before# a particular indexidx = [0] * N# Function to perform the point# update in Fenwick treedef update(index: int, val: int, bitt: list): while index < N: bitt[index] += val index += index & -index# Function to return the sum# of the elements A[1...idx]# from BITdef summation(index: int, bitt: list) -> int: res = 0 while index > 0: res += bitt[index] index -= index & -index return res# Function to perform the queries and# return the answer vectordef performQueries(A: list, B: list) -> list: global bit, idx # For 1 bases indexing # insert 0 in the vector A.insert(0, 0) # Updated size of the vector n = len(A) # Updating the bit tree for i in range(1
|