给定一个由N个整数组成的数组arr []和一个由以下两种类型的查询组成的2D数组Q [] [] :
- 1 LR:仅从一个设置位打印范围为[L,R]的数字计数。
- 2 XV:使用V更新第X个索引处的数组元素。
例子:
Input: arr[] = { 12, 11, 16, 2, 32 }, Q[][] = { { 1, 0, 2 }, { 2, 4, 24 }, { 1, 1, 4 } }
Output: 1 2
Explanation:
- Query 1: Print the count of array elements with only a single bit in the range of indices [0, 2], i.e. {16}.
- Query 2: Set arr[4] = 24. Therefore, the array arr[] modifies to {12, 11, 16, 24, 5}.
- Query 3: Print the count of array elements with only a single bit in the range of indices [1, 4], i.e. {16, 32}.
Input: arr[] = { 2, 1, 101, 11, 4 }, Q[][] = { { 1, 2, 4 }, { 2, 4, 12 }, { 1, 2, 4 } }
Output: 1 0
Explanation:
- Query 1: Print the count of array elements with only a single bit in the range of indices [2, 4], i.e. {4}.
- Query 2: Set arr[4] = 24, which modifies the array to arr[] = { 2, 1, 101, 11, 12}.
- Query 3: Print the count of array elements with only a single bit in the range of indices [2, 4]. But no array elements from the given range of indices contains only a single bit.
天真的方法:最简单的方法是遍历每个查询和每个元素的索引[L,R]范围内的数组,检查它是否恰好具有一个设置位。被发现为真的每个数组元素的增量计数。遍历整个范围后,打印count的值。对于类型2的查询,只需arr [X] = V。
时间复杂度: O(N * Q * log(N))
辅助空间: O(1)
高效方法:可以使用段树来优化上述方法。请按照以下步骤解决问题:
- 定义一个函数check(S)来检查整数是否仅包含一个设置位。
- 初始化3个变量: ss,se和si,以分别存储当前段的起点,当前段的终点和段树中的当前节点值。
- 定义一个函数,例如build_seg(ss,se,si)来构建一个分段树,类似于总和分段树,每个节点在其子树中仅存储一个位的元素计数:
- 如果ss == se,则tree [s [i]] =检查(arr [ss] )
- 否则,遍历左子树和右子树。
- 现在,将当前节点更新为tree [si] = tree [2 * si + 1] + tree [2 * si + 2]。
- 定义一个函数,例如update(ss,se,si,X,V) ,以指向更新数组arr []中的值:
- 如果当前节点是叶节点,即ss == se,则更新树[si] = check(V)。
- 否则,搜索第X个索引,即如果X≤(ss + se)/ 2,则遍历到左子树,即update(ss,mid,2 * si + 1,X,V)。否则,遍历右侧子树,即update(mid + 1,se,2 * si + 2,X,V)。
- 更新当前节点。
- 定义一个函数say查询(ss,se,si,L,R)以对仅具有[L,R]范围中的单个位的数字进行计数:
- 检查当前段[L,R]是否不与[ss,se]相交,然后返回0。
- 否则,如果ss> = L且se≤R,则返回tree [si] 。
- 如果以上条件都不满足,则返回query(ss,mid,L,R,2 * si +1)+ query(mid + 1,se,L,R,2 * si + 2) 。
- 对于类型{1,L,R}的查询,请打印查询(0,N-1,0,L,R)。
- 对于类型{2,X,V}的查询,请更新树中的值update(0,N-1,0,X,V) 。
下面是上述方法的实现:
C++
// C++ implementation
// for above approach
#include
using namespace std;
// Check if N has only
// one set bit
bool check(int N)
{
if (N == 0)
return 0;
return !(N & (N - 1));
}
// Function to build segment tree
void build_seg_tree(int ss, int se, int si,
int tree[], int arr[])
{
// If se is leaf node
if (ss == se) {
// Update the node
tree[si] = check(arr[ss]);
return;
}
// Stores mid value of segment [ss, se]
int mid = (ss + se) / 2;
// Recursive call for left Subtree
build_seg_tree(ss, mid,
2 * si + 1, tree, arr);
// Recursive call for right Subtree
build_seg_tree(mid + 1, se,
2 * si + 2, tree, arr);
// Update the Current Node
tree[si] = tree[2 * si + 1]
+ tree[2 * si + 2];
}
// Function to update a value at Xth index
void update(int ss, int se, int si,
int X, int V, int tree[], int arr[])
{
if (ss == se) {
// If ss is equal to X
if (ss == X) {
// Update the Xth node
arr[X] = V;
// Update the tree
tree[si] = check(V);
}
return;
}
// Stores the mid of segment [ss, se]
int mid = (ss + se) / 2;
if (X <= mid)
update(ss, mid, 2 * si + 1,
X, V, tree, arr);
else
update(mid + 1, se, 2 * si + 2,
X, V, tree, arr);
// Update current node
tree[si] = tree[2 * si + 1]
+ tree[2 * si + 2];
}
// Count of numbers
// having one set bit
int query(int l, int r, int ss,
int se, int si, int tree[])
{
// If L > se or R < ss
// Invalid Range
if (r < ss || l > se)
return 0;
// If [ss, se] lies
// inside the [L, R]
if (l <= ss && r >= se)
return tree[si];
// Stores the mid of segment [ss, se]
int mid = (ss + se) / 2;
// Return the sum after recursively
// traversing left and right subtree
return query(l, r, ss,
mid, 2 * si + 1, tree)
+ query(l, r, mid + 1,
se, 2 * si + 2, tree);
}
// Function to solve queries
void Query(int arr[], int N,
vector > Q)
{
// Initialise Segment tree
int tree[4 * N] = { 0 };
// Build segment tree
build_seg_tree(0, N - 1, 0, tree, arr);
// Perform queries
for (int i = 0; i < (int)Q.size(); i++) {
if (Q[i][0] == 1)
cout << query(Q[i][1], Q[i][2],
0, N - 1, 0, tree)
<< " ";
else
update(0, N - 1, 0, Q[i][1], Q[i][2], tree,
arr);
}
}
// Driver Code
int main()
{
// Input
int arr[] = { 12, 11, 16, 2, 32 };
vector > Q{ { 1, 0, 2 },
{ 2, 4, 24 },
{ 1, 1, 4 } };
int N = sizeof(arr) / sizeof(arr[0]);
// Function call to
// solve queries
Query(arr, N, Q);
return 0;
}
Java
/*package whatever //do not write package name here */
import java.io.*;
class GFG {
// Check if N has only
// one set bit
static int check(int N)
{
if (Integer.bitCount(N) == 1)
return 1;
else
return 0;
}
// Function to build segment tree
static void build_seg_tree(int ss, int se, int si,
int tree[], int arr[])
{
// If se is leaf node
if (ss == se)
{
// Update the node
tree[si] = check(arr[ss]);
return;
}
// Stores mid value of segment [ss, se]
int mid = (ss + se) / 2;
// Recursive call for left Subtree
build_seg_tree(ss, mid, 2 * si + 1, tree, arr);
// Recursive call for right Subtree
build_seg_tree(mid + 1, se, 2 * si + 2, tree, arr);
// Update the Current Node
tree[si] = tree[2 * si + 1] + tree[2 * si + 2];
}
// Function to update a value at Xth index
static void update(int ss, int se, int si, int X, int V,
int tree[], int arr[])
{
if (ss == se)
{
// If ss is equal to X
if (ss == X)
{
// Update the Xth node
arr[X] = V;
// Update the tree
tree[si] = check(V);
}
return;
}
// Stores the mid of segment [ss, se]
int mid = (ss + se) / 2;
if (X <= mid)
update(ss, mid, 2 * si + 1, X, V, tree, arr);
else
update(mid + 1, se, 2 * si + 2, X, V, tree,
arr);
// Update current node
tree[si] = tree[2 * si + 1] + tree[2 * si + 2];
}
// Count of numbers
// having one set bit
static int query(int l, int r, int ss,
int se, int si,
int tree[])
{
// If L > se or R < ss
// Invalid Range
if (r < ss || l > se)
return 0;
// If [ss, se] lies
// inside the [L, R]
if (l <= ss && r >= se)
return tree[si];
// Stores the mid of segment [ss, se]
int mid = (ss + se) / 2;
// Return the sum after recursively
// traversing left and right subtree
return query(l, r, ss, mid, 2 * si + 1, tree)
+ query(l, r, mid + 1, se, 2 * si + 2, tree);
}
// Function to solve queries
static void Query(int arr[], int N, int[][] Q)
{
// Initialise Segment tree
int tree[] = new int[4 * N];
// Build segment tree
build_seg_tree(0, N - 1, 0, tree, arr);
// Perform queries
for (int i = 0; i < Q.length; i++) {
if (Q[i][0] == 1)
System.out.print(query(Q[i][1], Q[i][2], 0,
N - 1, 0, tree) + " ");
else
update(0, N - 1, 0, Q[i][1], Q[i][2], tree,
arr);
}
}
// Driver Code
public static void main(String[] args)
{
int arr[] = { 12, 11, 16, 2, 32 };
int[][] Q
= { { 1, 0, 2 }, { 2, 4, 24 }, { 1, 1, 4 } };
int N = arr.length;
// Function call to
// solve queries
Query(arr, N, Q);
}
}
// This code is contributed by hemanthsawarna1506.
Python3
# Python3 implementation of
# the above approach
# Check if N has only
# one set bit
def check(N) :
if (N == 0):
return 0
return ((N & (N - 1)) == 0)
# Function to build segment tree
def build_seg_tree(ss, se, si, tree, arr) :
# If se is leaf node
if (ss == se) :
# Update the node
tree[si] = check(arr[ss])
return
# Stores mid value of segment [ss, se]
mid = (ss + se) // 2
# Recursive call for left Subtree
build_seg_tree(ss, mid,
2 * si + 1, tree, arr)
# Recursive call for right Subtree
build_seg_tree(mid + 1, se,
2 * si + 2, tree, arr)
# Update the Current Node
tree[si] = tree[2 * si + 1] + tree[2 * si + 2]
# Function to update a value at Xth index
def update(ss, se, si, X, V, tree, arr) :
if (ss == se) :
# If ss is equal to X
if (ss == X) :
# Update the Xth node
arr[X] = V
# Update the tree
tree[si] = check(V)
return
# Stores the mid of segment [ss, se]
mid = (ss + se) // 2
if (X <= mid):
update(ss, mid, 2 * si + 1,
X, V, tree, arr)
else :
update(mid + 1, se, 2 * si + 2,
X, V, tree, arr)
# Update current node
tree[si] = tree[2 * si + 1] + tree[2 * si + 2]
# Count of numbers
# having one set bit
def query(l, r, ss, se, si, tree) :
# If L > se or R < ss
# Invalid Range
if (r < ss or l > se):
return 0
# If [ss, se] lies
# inside the [L, R]
if (l <= ss and r >= se):
return tree[si]
# Stores the mid of segment [ss, se]
mid = (ss + se) // 2
# Return the sum after recursively
# traversing left and right subtree
return (query(l, r, ss, mid, 2 * si + 1, tree) + query(l, r, mid + 1, se, 2 * si + 2, tree))
# Function to solve queries
def Query(arr, N, Q) :
# Initialise Segment tree
tree = [0] * (4 * N)
# Build segment tree
build_seg_tree(0, N - 1, 0, tree, arr)
# Perform queries
for i in range(len(Q)):
if (Q[i][0] == 1):
print(query(Q[i][1], Q[i][2],
0, N - 1, 0, tree), end = " ")
else :
update(0, N - 1, 0, Q[i][1], Q[i][2], tree, arr)
# Driver Code
# Input
arr = [ 12, 11, 16, 2, 32 ]
Q = [ [ 1, 0, 2 ], [ 2, 4, 24 ], [ 1, 1, 4 ]]
N = len(arr)
# Function call to
# solve queries
Query(arr, N, Q)
# This code is contributed by code_hunt.
C#
// C# implementation
// for above approach
using System;
using System.Collections.Generic;
class GFG
{
// Check if N has only
// one set bit
static int check(int N)
{
if (N == 0 || (N & (N - 1)) != 0)
return 0;
return 1;
}
// Function to build segment tree
static void build_seg_tree(int ss, int se, int si,
int[] tree, int[] arr)
{
// If se is leaf node
if (ss == se)
{
// Update the node
tree[si] = check(arr[ss]);
return;
}
// Stores mid value of segment [ss, se]
int mid = (ss + se) / 2;
// Recursive call for left Subtree
build_seg_tree(ss, mid,
2 * si + 1, tree, arr);
// Recursive call for right Subtree
build_seg_tree(mid + 1, se,
2 * si + 2, tree, arr);
// Update the Current Node
tree[si] = tree[2 * si + 1]
+ tree[2 * si + 2];
}
// Function to update a value at Xth index
static void update(int ss, int se, int si,
int X, int V, int[] tree, int[] arr)
{
if (ss == se)
{
// If ss is equal to X
if (ss == X)
{
// Update the Xth node
arr[X] = V;
// Update the tree
tree[si] = check(V);
}
return;
}
// Stores the mid of segment [ss, se]
int mid = (ss + se) / 2;
if (X <= mid)
update(ss, mid, 2 * si + 1,
X, V, tree, arr);
else
update(mid + 1, se, 2 * si + 2,
X, V, tree, arr);
// Update current node
tree[si] = tree[2 * si + 1]
+ tree[2 * si + 2];
}
// Count of numbers
// having one set bit
static int query(int l, int r, int ss,
int se, int si, int[] tree)
{
// If L > se or R < ss
// Invalid Range
if (r < ss || l > se)
return 0;
// If [ss, se] lies
// inside the [L, R]
if (l <= ss && r >= se)
return tree[si];
// Stores the mid of segment [ss, se]
int mid = (ss + se) / 2;
// Return the sum after recursively
// traversing left and right subtree
return query(l, r, ss,
mid, 2 * si + 1, tree)
+ query(l, r, mid + 1,
se, 2 * si + 2, tree);
}
// Function to solve queries
static void Query(int[] arr, int N,
List > Q)
{
// Initialise Segment tree
int[] tree = new int[4 * N];
// Build segment tree
build_seg_tree(0, N - 1, 0, tree, arr);
// Perform queries
for (int i = 0; i < (int)Q.Count; i++)
{
if (Q[i][0] == 1)
Console.Write(query(Q[i][1], Q[i][2], 0, N - 1, 0, tree) + " ");
else
update(0, N - 1, 0, Q[i][1], Q[i][2], tree, arr);
}
}
// Driver code
static void Main()
{
// Input
int[] arr = { 12, 11, 16, 2, 32 };
List > Q = new List>();
Q.Add(new List(new int[]{1, 0, 2}));
Q.Add(new List(new int[]{2, 4, 24}));
Q.Add(new List(new int[]{1, 1, 4}));
int N = arr.Length;
// Function call to
// solve queries
Query(arr, N, Q);
}
}
// This code is contributed by divyeshrabadiya07
输出:
1 2
时间复杂度: O(N * log(N)+ Q * log(N))
辅助空间: O(1)