给定两个大小分别为N和Q 的数组arr[]和query[]以及一个整数M ,每个查询的任务是计算大于或等于query[i]的数组元素的数量并减少所有这些按M编号,并对更新后的数组执行其余查询。
例子:
Input: arr[] = {1, 2, 3, 4}, query[] = {4, 3, 1}, M = 1
Output: 1 2 4
Explanation:
query[0]: Count of array elements which are greater than or equal to 4 in arr[] is 1 and decreasing the number by M modifies array to {1, 2, 3, 3}.
query[1]: Count of array elements which are greater than or equal to 3 in arr[] is 2 and decreasing all such numbers by M modifies array to {1, 2, 2, 2}.
query[2]: Count of array elements which are greater than or equal to 1 in arr[] is 4 and decreasing all such numbers by M modifies array to {0, 1, 1, 1}.
Input: arr[] = {1, 2, 3}, query = {3, 3}, M = 2
Output: 1 0
Explanation:
query[0]: Count of array elements which are greater than or equal to in arr[] is 1 and decreasing that number by M modifies array to arr[] = {1, 2, 1}.
query[1]: Count of array elements which are greater than or equal to 3 in arr[] is 0. So the array remains unchanged.
朴素的方法:最简单的方法是为每个查询迭代整个数组,并检查当前数组元素是否大于或等于query[i] 。对于发现上述条件为真的元素,将该元素减去M并增加计数。最后打印每个查询的计数。
时间复杂度: O(Q * N)
辅助空间: O(1)
有效的方法:可以使用段树来解决这个问题。
- 首先,按非降序对数组arr[]进行排序。
- 现在,找到元素的第一个位置,比如说l ,它包含一个元素>= query[i] 。
- 如果不存在这样的元素,则该查询的答案将为0 。否则答案将是N – l 。
- 最后更新给定范围l到N – 1 中的线段树,并从给定范围内的所有元素中减去M。
Illustration:
Consider the following example : arr[] = {1, 2, 3, 4}, query[] = {4, 3, 1}, M = 1
After sorting arr[] = {1, 2, 3, 4}.
query[0]: K = 4 and arr[3] >= 4 so l = 3 and result = 4 – 3 = 1 and updated arr[] = {1, 2, 3, 3}
query[1]: K = 3 and arr[2] >=3 so l = 2 and result = 4 – 2 = 2 and updated arr[] = {1, 2, 2, 2}
query[2]: K = 1 and arr[0] >=1 so l = 0 and result = 4 – 0 = 4 and updated arr[] = {0, 1, 1, 1}
下面是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
// Function to build a segment tree
void build(vector& sum,
vector& a,
int l, int r, int rt)
{
// Check for base case
if (l == r) {
sum[rt] = a[l - 1];
return;
}
// Find mid point
int m = (l + r) >> 1;
// Recursively build the
// segment tree
build(sum, a, l, m, rt << 1);
build(sum, a, m + 1, r, rt << 1 | 1);
}
// Function for push down operation
// on the segment tree
void pushDown(vector& sum,
vector& add,
int rt, int ln, int rn)
{
if (add[rt]) {
add[rt << 1] += add[rt];
add[rt << 1 | 1] += add[rt];
sum[rt << 1] += add[rt] * ln;
sum[rt << 1 | 1] += add[rt] * rn;
add[rt] = 0;
}
}
// Function to update the segment tree
void update(vector& sum,
vector& add,
int L, int R, int C, int l,
int r, int rt)
{
// Complete overlap
if (L <= l && r <= R) {
sum[rt] += C * (r - l + 1);
add[rt] += C;
return;
}
// Find mid
int m = (l + r) >> 1;
// Perform push down operation
// on segment tree
pushDown(sum, add, rt, m - l + 1,
r - m);
// Recursively update the segment tree
if (L <= m)
update(sum, add, L, R, C, l, m,
rt << 1);
if (R > m)
update(sum, add, L, R, C, m + 1, r,
rt << 1 | 1);
}
// Function to process the query
int query(vector& sum,
vector& add,
int L, int R, int l,
int r, int rt)
{
// Base case
if (L <= l && r <= R) {
return sum[rt];
}
// Find mid
int m = (l + r) >> 1;
// Perform push down operation
// on segment tree
pushDown(sum, add, rt, m - l + 1,
r - m);
int ans = 0;
// Recursively calculate the result
// of the query
if (L <= m)
ans += query(sum, add, L, R, l, m,
rt << 1);
if (R > m)
ans += query(sum, add, L, R, m + 1, r,
rt << 1 | 1);
// Return the result
return ans;
}
// Function to count the numbers
// which are greater than the given query
void sequenceMaintenance(int n, int q,
vector& a,
vector& b,
int m)
{
// Sort the input array
sort(a.begin(), a.end());
// Create segment tree of size 4*n
vector sum, add, ans;
sum.assign(n << 2, 0);
add.assign(n << 2, 0);
// Build the segment tree
build(sum, a, 1, n, 1);
// Iterate over the queries
for (int i = 0; i < q; i++) {
int l = 1, r = n, pos = -1;
while (l <= r) {
int m = (l + r) >> 1;
if (query(sum, add, m, m, 1, n, 1)
>= b[i]) {
r = m - 1;
pos = m;
}
else {
l = m + 1;
}
}
if (pos == -1)
ans.push_back(0);
else {
// Store result in array
ans.push_back(n - pos + 1);
// Update the elements in
// the given range
update(sum, add, pos, n, -m,
1, n, 1);
}
}
// Print the result of queries
for (int i = 0; i < ans.size(); i++) {
cout << ans[i] << " ";
}
}
// Driver Code
int main()
{
int N = 4;
int Q = 3;
int M = 1;
vector arr = { 1, 2, 3, 4 };
vector query = { 4, 3, 1 };
// Function Call
sequenceMaintenance(N, Q, arr, query, M);
return 0;
}
Java
// Java program for the above approach
import java.io.*;
import java.util.*;
class GFG
{
// Function to build a segment tree
static void build(Vector sum,Vector a,
int l, int r, int rt)
{
// Check for base case
if(l == r)
{
sum.set(rt, a.get(l - 1));
return;
}
// Find mid point
int m = (l + r) >> 1;
// Recursively build the
// segment tree
build(sum, a, l, m, rt << 1);
build(sum, a, m + 1, r, rt << 1 | 1);
}
// Function for push down operation
// on the segment tree
static void pushDown(Vector sum,
Vector add,
int rt, int ln, int rn)
{
if(add.get(rt) != 0)
{
add.set(rt << 1, add.get(rt));
add.set(rt << 1 | 1, add.get(rt));
sum.set(rt << 1, sum.get(rt << 1) + add.get(rt) * ln);
sum.set(rt << 1 | 1, sum.get(rt << 1 | 1) + add.get(rt) * rn);
add.set(rt, 0);
}
}
// Function to update the segment tree
static void update(Vector sum,
Vector add,int L,
int R, int C, int l, int r, int rt)
{
// Complete overlap
if(L <= l && r <= R)
{
sum.set(rt,sum.get(rt) + C * (r - l + 1));
add.set(rt,add.get(rt) + C);
return;
}
// Find mid
int m = (l + r) >> 1;
// Perform push down operation
// on segment tree
pushDown(sum, add, rt, m - l + 1, r - m);
// Recursively update the segment tree
if(L <= m)
{
update(sum, add, L, R, C, l, m, rt << 1);
}
if(R > m)
{
update(sum, add, L, R, C, m + 1, r, rt << 1 | 1);
}
}
// Function to process the query
static int query(Vector sum,Vector add,
int L, int R, int l,int r, int rt)
{
// Base case
if (L <= l && r <= R)
{
return sum.get(rt);
}
// Find mid
int m = (l + r) >> 1;
// Perform push down operation
// on segment tree
pushDown(sum, add, rt, m - l + 1, r - m);
int ans = 0;
// Recursively calculate the result
// of the query
if(L <= m)
{
ans += query(sum, add, L, R, l, m, rt << 1);
}
if(R > m)
{
ans += query(sum, add, L, R, m + 1, r,rt << 1 | 1);
}
// Return the result
return ans;
}
// Function to count the numbers
// which are greater than the given query
static void sequenceMaintenance(int n, int q,
Vector a,
Vector b,int m)
{
// Sort the input array
Collections.sort(a);
// Create segment tree of size 4*n
Vector sum = new Vector();
Vector ad = new Vector();
Vector ans = new Vector();
for(int i = 0; i < (n << 2); i++)
{
sum.add(0);
ad.add(0);
}
// Build the segment tree
build(sum, a, 1, n, 1);
// Iterate over the queries
for(int i = 0; i < q; i++)
{
int l = 1, r = n, pos = -1;
while(l <= r)
{
m = (l + r) >> 1;
if(query(sum, ad, m, m, 1, n, 1) >= b.get(i))
{
r = m - 1;
pos = m;
}
else
{
l = m + 1;
}
}
if(pos == -1)
{
ans.add(0);
}
else
{
// Store result in array
ans.add(n - pos + 1);
// Update the elements in
// the given range
update(sum, ad, pos, n, -m, 1, n, 1);
}
}
// Print the result of queries
for(int i = 0; i < ans.size(); i++)
{
System.out.print(ans.get(i) + " ");
}
}
// Driver Code
public static void main (String[] args)
{
int N = 4;
int Q = 3;
int M = 1;
Vector arr = new Vector();
arr.add(1);
arr.add(2);
arr.add(3);
arr.add(4);
Vector query = new Vector();
query.add(4);
query.add(3);
query.add(1);
// Function call
sequenceMaintenance(N, Q, arr, query, M);
}
}
// This code is contributed by rag2127
Python3
# Python3 program for the above approach
# Function to build a segment tree
def build(sum, a, l, r, rt):
# Check for base case
if (l == r):
sum[rt] = a[l - 1]
return
# Find mid point
m = (l + r) >> 1
# Recursively build the
# segment tree
build(sum, a, l, m, rt << 1)
build(sum, a, m + 1, r, rt << 1 | 1)
# Function for push down operation
# on the segment tree
def pushDown(sum, add, rt, ln, rn):
if (add[rt]):
add[rt << 1] += add[rt]
add[rt << 1 | 1] += add[rt]
sum[rt << 1] += add[rt] * ln
sum[rt << 1 | 1] += add[rt] * rn
add[rt] = 0
# Function to update the segment tree
def update(sum, add, L, R, C, l, r, rt):
# Complete overlap
if (L <= l and r <= R):
sum[rt] += C * (r - l + 1)
add[rt] += C
return
# Find mid
m = (l + r) >> 1
# Perform push down operation
# on segment tree
pushDown(sum, add, rt, m - l + 1, r - m)
# Recursively update the segment tree
if (L <= m):
update(sum, add, L, R, C, l,
m, rt << 1)
if (R > m):
update(sum, add, L, R, C, m + 1,
r, rt << 1 | 1)
# Function to process the queryy
def queryy(sum, add, L, R, l, r, rt):
# Base case
if (L <= l and r <= R):
return sum[rt]
# Find mid
m = (l + r) >> 1
# Perform push down operation
# on segment tree
pushDown(sum, add, rt, m - l + 1, r - m)
ans = 0
# Recursively calculate the result
# of the queryy
if (L <= m):
ans += queryy(sum, add, L, R, l,
m, rt << 1)
if (R > m):
ans += queryy(sum, add, L, R, m + 1,
r, (rt << 1 | 1))
# Return the result
return ans
# Function to count the numbers
# which are greater than the given queryy
def sequenceMaintenance(n, q, a, b, m):
# Sort the input array
a = sorted(a)
# Create segment tree of size 4*n
# vector sum, add, ans
sum = [0] * (4 * n)
add = [0] * (4 * n)
ans = []
# Build the segment tree
build(sum, a, 1, n, 1)
#print(sum)
# Iterate over the queries
for i in range(q):
l = 1
r = n
pos = -1
while (l <= r):
m = (l + r) >> 1
if (queryy(sum, add, m, m,
1, n, 1) >= b[i]):
r = m - 1
pos = m
else:
l = m + 1
if (pos == -1):
ans.append(0)
else:
# Store result in array
ans.append(n - pos + 1)
# Update the elements in
# the given range
update(sum, add, pos, n,
-m, 1, n, 1)
# Print the result of queries
for i in ans:
print(i, end = " ")
# Driver Code
if __name__ == '__main__':
N = 4
Q = 3
M = 1
arr = [ 1, 2, 3, 4 ]
query = [ 4, 3, 1 ]
# Function call
sequenceMaintenance(N, Q, arr, query, M)
# This code is contributed by mohit kumar 29
C#
// C# program for the above approach
using System;
using System.Collections;
using System.Collections.Generic;
class GFG{
// Function to build a segment tree
static void build(ArrayList sum,
ArrayList a,
int l, int r,
int rt)
{
// Check for base case
if (l == r)
{
sum[rt] = a[l - 1];
return;
}
// Find mid point
int m = (l + r) >> 1;
// Recursively build the
// segment tree
build(sum, a, l, m, rt << 1);
build(sum, a, m + 1, r, rt << 1 | 1);
}
// Function for push down operation
// on the segment tree
static void pushDown(ArrayList sum,
ArrayList add,
int rt, int ln,
int rn)
{
if ((int)add[rt] != 0)
{
add[rt << 1] = (int)add[rt << 1] +
(int)add[rt];
add[rt << 1 | 1] = (int)add[rt << 1 | 1] +
(int)add[rt];
sum[rt << 1] = (int)sum[rt << 1] +
(int)add[rt] * ln;
sum[rt << 1 | 1] = (int)sum[rt << 1 | 1] +
(int)add[rt] * rn;
add[rt] = 0;
}
}
// Function to update the segment tree
static void update(ArrayList sum,
ArrayList add,
int L, int R, int C,
int l, int r, int rt)
{
// Complete overlap
if (L <= l && r <= R)
{
sum[rt] = (int)sum[rt] +
C * (r - l + 1);
add[rt] = (int)add[rt] + C;
return;
}
// Find mid
int m = (l + r) >> 1;
// Perform push down operation
// on segment tree
pushDown(sum, add, rt, m - l + 1,
r - m);
// Recursively update the segment tree
if (L <= m)
update(sum, add, L, R, C, l, m,
rt << 1);
if (R > m)
update(sum, add, L, R, C, m + 1, r,
rt << 1 | 1);
}
// Function to process the query
static int query(ArrayList sum,
ArrayList add,
int L, int R, int l,
int r, int rt)
{
// Base case
if (L <= l && r <= R)
{
return (int)sum[rt];
}
// Find mid
int m = (l + r) >> 1;
// Perform push down operation
// on segment tree
pushDown(sum, add, rt, m - l + 1,
r - m);
int ans = 0;
// Recursively calculate the result
// of the query
if (L <= m)
ans += query(sum, add, L, R, l, m,
rt << 1);
if (R > m)
ans += query(sum, add, L, R, m + 1, r,
rt << 1 | 1);
// Return the result
return ans;
}
// Function to count the numbers
// which are greater than the given query
static void sequenceMaintenance(int n, int q,
ArrayList a,
ArrayList b,
int m)
{
// Sort the input array
a.Sort();
// Create segment tree of size 4*n
ArrayList sum = new ArrayList();
ArrayList add = new ArrayList();
ArrayList ans = new ArrayList();
for(int i = 0; i < (n << 2); i++)
{
sum.Add(0);
add.Add(0);
}
// Build the segment tree
build(sum, a, 1, n, 1);
// Iterate over the queries
for(int i = 0; i < q; i++)
{
int l = 1, r = n, pos = -1;
while (l <= r)
{
m = (l + r) >> 1;
if (query(sum, add, m, m,
1, n, 1) >= (int)b[i])
{
r = m - 1;
pos = m;
}
else
{
l = m + 1;
}
}
if (pos == -1)
ans.Add(0);
else
{
// Store result in array
ans.Add(n - pos + 1);
// Update the elements in
// the given range
update(sum, add, pos, n, -m,
1, n, 1);
}
}
// Print the result of queries
for(int i = 0; i < ans.Count; i++)
{
Console.Write(ans[i] + " ");
}
}
// Driver Code
public static void Main(string[] args)
{
int N = 4;
int Q = 3;
int M = 1;
ArrayList arr = new ArrayList(){ 1, 2, 3, 4 };
ArrayList query = new ArrayList(){ 4, 3, 1 };
// Function call
sequenceMaintenance(N, Q, arr, query, M);
}
}
// This code is contributed by rutvik_56
1 2 4
时间复杂度: O (N + (Q * logN))
辅助空间: O (N)
如果您想与行业专家一起参加直播课程,请参阅Geeks Classes Live