给定一个大小为N的数组arr []和一个二维数组Q [] [] ,该数组由以下两种类型的查询组成:
- 1 XY:用Y更新索引X处的数组元素。
- 2 K:打印第一个数组元素的位置大于或等于K。如果没有这样的索引,则打印-1 。
例子:
Input : arr[] = { 1, 3, 2, 4, 6 }, Q[][] = {{2, 5}, {1, 3, 5}, {2, 4}, {2, 8}}
Output: 5 3 -1
Explanation:
Query1: Since arr[4] > 5, the position of arr[4] is 5.
Query2: Updating arr[2] with 5 modifies arr[] to {1, 3, 5, 4, 6}
Query3: Since arr[2] > 4, the position of arr[4] is 5.
Query4: No array element is greater than 8.
Input : arr[] = {1, 2, 3}, N = 3, Q[][] = {{2, 2}, {1, 3, 5}, {2, 10}}
Output: 2 -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