Queries to count array elements from a given range having a single set bit
Given an array arr[] consisting of N integers and a 2D array Q[][] consisting of queries of the following two types:
- 1 L R: Print the count of numbers from the range [L, R] having only a single set bit.
- 2 X V: Update the array element at Xth index with V.
Examples:
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.
Naive Approach: The simplest approach is to traverse the array over the range of indices [L, R] for each query and for each element, check if it has exactly one set bit or not. Increment count for every array element for which it is found to be true. After traversing the entire range, print the value of count. For queries of type 2, simply arr[X] = V.
Time Complexity: O(N * Q * log(N))
Auxiliary Space: O(1)
Efficient Approach: The above approach can be optimized using a Segment Tree. Follow the steps below to solve the problem:
- Define a function, check(S) to check if integer contains only one set bit.
- Initialize 3 variables: ss, se, and si to store the starting point of the current segment, ending point of the current segment, and current node value in the segment tree respectively.
- Define a function, say build_seg(ss, se, si), to build a segment tree Similar to the sum segment tree, each node storing the count of elements with only a single bit in its subtree:
- If ss == se, tree[s[i]] = check (arr[ss] )
- Otherwise, traverse the left subtree and right subtree.
- Now, update the current node as tree[si] = tree[2 * si + 1]+ tree[2 * si + 2].
- Define a function, say update( ss, se, si, X, V), to point update a value in the array arr[]:
- If current node is leaf node, i.e ss == se then update the tree[si] = check(V).
- Otherwise, search for the Xth index i.e if X ? (ss + se) / 2 then Traverse to the left subtree i.e update(ss, mid, 2 * si + 1, X, V). Otherwise, traverse to the right subtree i.e update(mid + 1, se, 2 * si + 2, X, V).
- Update the current node.
- Define a function say query(ss, se, si, L, R) to count numbers having only a single bit in the range [L, R]:
- Check if the current segment [L, R] does not intersect with [ss, se] then return 0.
- Otherwise, if ss >= L and se ? R then return tree[si].
- If none of the above conditions satisfies then return query(ss, mid, L, R, 2 * si + 1)+query(mid + 1, se, L, R, 2 * si + 2).
- For query of type { 1, L, R }, print the query(0, N-1, 0, L, R).
- For query of type { 2, X, V }, update the value in the tree, update(0, N-1, 0, X, V).
Below is the implementation of the above approach:
// C++ implementation
// for above approach
#include <bits/stdc++.h>
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<vector<int> > 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<vector<int> > 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;
}
// C++ implementation
// for above approach
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<vector<int> > 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<vector<int> > 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;
}
/*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 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# 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<List<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 < (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<List<int> > Q = new List<List<int>>();
Q.Add(new List<int>(new int[]{1, 0, 2}));
Q.Add(new List<int>(new int[]{2, 4, 24}));
Q.Add(new List<int>(new int[]{1, 1, 4}));
int N = arr.Length;
// Function call to
// solve queries
Query(arr, N, Q);
}
}
// This code is contributed by divyeshrabadiya07
<script>
// JavaScript implementation
// for above approach
// Check if N has only
// one set bit
function check( N)
{
if (N == 0)
return 0;
return !(N & (N - 1));
}
// Function to build segment tree
function 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]
var mid = parseInt((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
function 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]
var mid = parseInt((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
function query( l, r, ss, se, si, 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]
var mid = parseInt((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
function Query(arr, N, Q)
{
// Initialise Segment tree
var tree = new Array(4 * N);
tree.fill( 0 );
// Build segment tree
build_seg_tree(0, N - 1, 0, tree, arr);
// Perform queries
for (var i = 0; i < Q.length; i++) {
if (Q[i][0] == 1)
document.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);
}
}
var arr = [ 12, 11, 16, 2, 32 ];
var Q = [ [1, 0, 2 ],
[ 2, 4, 24],
[ 1, 1, 4 ] ];
var N = arr.length;
// Function call to
// solve queries
Query(arr, N, Q);
// This code is contributed by SoumikMondal
</script>
Output
1 2
Time Complexity: O(N*log(N)+Q*log(N))
Auxiliary Space: O(N)
Approach using Fenwick Tree
To optimize the process of handling the two types of queries, we can utilize a Fenwick Tree (Binary Indexed Tree, BIT). This tree structure is especially effective for cumulative frequency tables and can efficiently update elements and query prefix sums. In this scenario, we maintain a BIT that holds counts of numbers with a single set bit. This allows us to achieve faster updates and range queries, reducing complexity compared to a Segment Tree.
Why Use Fenwick Tree for this Problem:
- Faster Updates: The Fenwick Tree provides a way to update an element in logarithmic time.
- Efficient Range Queries: It allows sum queries (or in our case, count queries) over a range in logarithmic time after an O(N log N) preprocessing time.
- Space Efficiency: It uses space proportional to the array size, which is optimal for the operations it supports.
Steps in the Solution:
- Initial Construction: Convert the initial array into a form suitable for the Fenwick Tree, marking each position based on whether the number has a single set bit.
- Update Function: Modify the tree when an update occurs, ensuring the counts reflect the change.
- Query Function: Efficiently compute the number of elements with a single set bit in any given range.
#include <iostream>
#include <vector>
// Function to check if a number is a power of two using
// bitwise operation
bool isPowerOfTwo(int x)
{
// x & (x - 1) removes the lowest set bit, if zero then
// it's power of two
return (x != 0) && ((x & (x - 1)) == 0);
}
// Function to update a value in Fenwick Tree
void update(std::vector<int>& fenwick, int idx, int value,
int n)
{
// Start from index 'idx' and update all relevant
// indices in the tree
while (idx <= n) {
fenwick[idx]
+= value; // Increment the value at this index
idx += idx
& -idx; // Move to next index to be updated
}
}
// Function to build the Fenwick Tree from the given array
std::vector<int> buildFenwick(const std::vector<int>& arr)
{
int n = arr.size();
std::vector<int> fenwick(n + 1, 0);
for (int i = 0; i < n; ++i) {
if (isPowerOfTwo(arr[i])) {
update(fenwick, i + 1, 1,
n); // Only count 1 if the element is a
// power of two
}
}
return fenwick;
}
// Function to get the sum from index 1 to 'idx' in the
// Fenwick Tree
int sumQuery(const std::vector<int>& fenwick, int idx)
{
int sum = 0;
while (idx > 0) {
sum += fenwick[idx]; // Add the current index's
// value to the sum
idx -= idx & -idx; // Move to the next contributing
// element in the tree
}
return sum;
}
// Function to get the sum between indices 'l' and 'r' in
// the original array
int rangeQuery(const std::vector<int>& fenwick, int l,
int r)
{
return sumQuery(fenwick, r + 1) - sumQuery(fenwick, l);
}
// Function to handle queries and updates on the array
std::vector<int>
handleQueries(std::vector<int>& arr,
const std::vector<std::vector<int> >& queries)
{
std::vector<int> fenwick = buildFenwick(arr);
std::vector<int> results;
int n = arr.size();
for (const auto& query : queries) {
if (query[0] == 1) {
// Query type 1: count elements with single set
// bit between l and r
int l = query[1], r = query[2];
results.push_back(rangeQuery(fenwick, l, r));
}
else if (query[0] == 2) {
// Query type 2: update element at index idx
// with value val
int idx = query[1], val = query[2];
int current_val
= isPowerOfTwo(arr[idx]) ? 1 : 0;
int new_val = isPowerOfTwo(val) ? 1 : 0;
update(fenwick, idx + 1, new_val - current_val,
n);
arr[idx] = val;
}
}
return results;
}
// Driver code
int main()
{
std::vector<int> arr = { 12, 11, 16, 2, 32 };
std::vector<std::vector<int> > queries
= { { 1, 0, 2 }, { 2, 4, 24 }, { 1, 1, 4 } };
std::vector<int> result = handleQueries(arr, queries);
for (int res : result) {
std::cout << res << " ";
}
std::cout << std::endl;
return 0;
}
// Function to check if a number is a power of two using
// bitwise operation
bool isPowerOfTwo(int x)
{
// x & (x - 1) removes the lowest set bit, if zero then
// it's power of two
return (x != 0) && ((x & (x - 1)) == 0);
}
// Function to update a value in Fenwick Tree
void update(std::vector<int>& fenwick, int idx, int value,
int n)
{
// Start from index 'idx' and update all relevant
// indices in the tree
while (idx <= n) {
fenwick[idx]
+= value; // Increment the value at this index
idx += idx
& -idx; // Move to next index to be updated
}
}
// Function to build the Fenwick Tree from the given array
std::vector<int> buildFenwick(const std::vector<int>& arr)
{
int n = arr.size();
std::vector<int> fenwick(n + 1, 0);
for (int i = 0; i < n; ++i) {
if (isPowerOfTwo(arr[i])) {
update(fenwick, i + 1, 1,
n); // Only count 1 if the element is a
// power of two
}
}
return fenwick;
}
// Function to get the sum from index 1 to 'idx' in the
// Fenwick Tree
int sumQuery(const std::vector<int>& fenwick, int idx)
{
int sum = 0;
while (idx > 0) {
sum += fenwick[idx]; // Add the current index's
// value to the sum
idx -= idx & -idx; // Move to the next contributing
// element in the tree
}
return sum;
}
// Function to get the sum between indices 'l' and 'r' in
// the original array
int rangeQuery(const std::vector<int>& fenwick, int l,
int r)
{
return sumQuery(fenwick, r + 1) - sumQuery(fenwick, l);
}
// Function to handle queries and updates on the array
std::vector<int>
handleQueries(std::vector<int>& arr,
const std::vector<std::vector<int> >& queries)
{
std::vector<int> fenwick = buildFenwick(arr);
std::vector<int> results;
int n = arr.size();
for (const auto& query : queries) {
if (query[0] == 1) {
// Query type 1: count elements with single set
// bit between l and r
int l = query[1], r = query[2];
results.push_back(rangeQuery(fenwick, l, r));
}
else if (query[0] == 2) {
// Query type 2: update element at index idx
// with value val
int idx = query[1], val = query[2];
int current_val
= isPowerOfTwo(arr[idx]) ? 1 : 0;
int new_val = isPowerOfTwo(val) ? 1 : 0;
update(fenwick, idx + 1, new_val - current_val,
n);
arr[idx] = val;
}
}
return results;
}
// Driver code
int main()
{
std::vector<int> arr = { 12, 11, 16, 2, 32 };
std::vector<std::vector<int> > queries
= { { 1, 0, 2 }, { 2, 4, 24 }, { 1, 1, 4 } };
std::vector<int> result = handleQueries(arr, queries);
for (int res : result) {
std::cout << res << " ";
}
std::cout << std::endl;
return 0;
}
import java.util.ArrayList;
import java.util.List;
public class Main {
// Function to check if a number is a power of two using
// bitwise operation
static boolean isPowerOfTwo(int x)
{
// x & (x - 1) removes the lowest set bit, if zero
// then it's power of two
return (x != 0) && ((x & (x - 1)) == 0);
}
// Function to update a value in Fenwick Tree
static void update(List<Integer> fenwick, int idx,
int value)
{
// Start from index 'idx' and update all relevant
// indices in the tree
while (idx < fenwick.size()) {
fenwick.set(idx,
fenwick.get(idx)
+ value); // Increment the value
// at this index
idx += idx & -idx; // Move to next index to be
// updated
}
}
// Function to build the Fenwick Tree from the given
// array
static List<Integer> buildFenwick(List<Integer> arr)
{
int n = arr.size();
List<Integer> fenwick = new ArrayList<>(n + 1);
for (int i = 0; i <= n; i++) {
fenwick.add(0);
}
for (int i = 0; i < n; ++i) {
if (isPowerOfTwo(arr.get(i))) {
update(fenwick, i + 1,
1); // Only count 1 if the element is
// a power of two
}
}
return fenwick;
}
// Function to get the sum from index 1 to 'idx' in the
// Fenwick Tree
static int sumQuery(List<Integer> fenwick, int idx)
{
int sum = 0;
while (idx > 0) {
sum += fenwick.get(
idx); // Add the current index's value to
// the sum
idx -= idx
& -idx; // Move to the next contributing
// element in the tree
}
return sum;
}
// Function to get the sum between indices 'l' and 'r'
// in the original array
static int rangeQuery(List<Integer> fenwick, int l,
int r)
{
return sumQuery(fenwick, r + 1)
- sumQuery(fenwick, l);
}
// Function to handle queries and updates on the array
static List<Integer>
handleQueries(List<Integer> arr,
List<List<Integer> > queries)
{
List<Integer> fenwick = buildFenwick(arr);
List<Integer> results = new ArrayList<>();
int n = arr.size();
for (List<Integer> query : queries) {
if (query.get(0) == 1) {
// Query type 1: count elements with single
// set bit between l and r
int l = query.get(1), r = query.get(2);
results.add(rangeQuery(fenwick, l, r));
}
else if (query.get(0) == 2) {
// Query type 2: update element at index idx
// with value val
int idx = query.get(1), val = query.get(2);
int currentVal
= isPowerOfTwo(arr.get(idx)) ? 1 : 0;
int newVal = isPowerOfTwo(val) ? 1 : 0;
update(fenwick, idx + 1,
newVal - currentVal);
arr.set(idx, val);
}
}
return results;
}
// Driver code
public static void main(String[] args)
{
List<Integer> arr
= new ArrayList<>(List.of(12, 11, 16, 2, 32));
List<List<Integer> > queries
= List.of(List.of(1, 0, 2), List.of(2, 4, 24),
List.of(1, 1, 4));
List<Integer> result = handleQueries(arr, queries);
for (int res : result) {
System.out.print(res + " ");
}
System.out.println();
}
}
def is_power_of_two(x):
# Returns True if x is a power of two, checked by bitwise operation
# (x & (x - 1)) == 0 checks if x has only one bit set, which is true for powers of two
return (x != 0) and (x & (x - 1)) == 0
def update(fenwick, idx, value, n):
# Updates the Fenwick tree (binary indexed tree) at index 'idx' by 'value'
# 'n' is the size of the original array for bounds checking
while idx <= n:
fenwick[idx] += value # Increment the current index by the value
idx += idx & -idx # Move to the next index that is responsible for this index
def build_fenwick(arr):
# Constructs and returns a Fenwick tree from the given array 'arr'
# Only counts 1 if the element is a power of two
n = len(arr)
fenwick = [0] * (n + 1) # Fenwick tree size is n + 1
for i in range(n):
if is_power_of_two(arr[i]):
# Update Fenwick tree if the element is a power of two
update(fenwick, i + 1, 1, n)
return fenwick
def sum_query(fenwick, idx):
# Computes the prefix sum from the start to the 'idx' in the Fenwick tree
s = 0
while idx > 0:
s += fenwick[idx] # Add current index value to sum
idx -= idx & -idx # Move to next responsible index
return s
def range_query(fenwick, l, r):
# Computes the range sum from index 'l' to 'r' in the original array using the Fenwick tree
# Utilize prefix sums for range sum
return sum_query(fenwick, r + 1) - sum_query(fenwick, l)
def handle_queries(arr, queries):
# Processes each query on the array 'arr' using a Fenwick tree for efficient range queries and updates
fenwick = build_fenwick(arr) # Initial Fenwick tree based on array 'arr'
n = len(arr)
results = [] # To store results of type 1 queries
for query in queries:
if query[0] == 1:
# Query of type 1: Count elements with single set bit between indices 'l' and 'r'
l, r = query[1], query[2]
results.append(range_query(fenwick, l, r))
elif query[0] == 2:
# Query of type 2: Update element at index 'idx' with value 'val'
idx, val = query[1], query[2]
# Check if current arr[idx] is a power of two
current_val = 1 if is_power_of_two(arr[idx]) else 0
# Check if new value 'val' is a power of two
new_val = 1 if is_power_of_two(val) else 0
# Update the Fenwick tree
update(fenwick, idx + 1, new_val - current_val, n)
arr[idx] = val # Update the array
return results
# Example usage
arr = [12, 11, 16, 2, 32]
queries = [[1, 0, 2], [2, 4, 24], [1, 1, 4]]
result = handle_queries(arr, queries)
print(result) # Output: [1, 2]
// Function to check if a number is a power of two using bitwise operation
const isPowerOfTwo = x => (x !== 0) && ((x & (x - 1)) === 0);
// Function to update a value in Fenwick Tree
const update = (fenwick, idx, value) => {
while (idx < fenwick.length) {
fenwick[idx] += value;
idx += idx & -idx;
}
}
// Function to build the Fenwick Tree from the given array
const buildFenwick = arr => {
const n = arr.length;
const fenwick = new Array(n + 1).fill(0);
for (let i = 0; i < n; ++i) {
if (isPowerOfTwo(arr[i])) {
update(fenwick, i + 1, 1);
}
}
return fenwick;
}
// Function to get the sum from index 1 to 'idx' in the Fenwick Tree
const sumQuery = (fenwick, idx) => {
let sum = 0;
while (idx > 0) {
sum += fenwick[idx];
idx -= idx & -idx;
}
return sum;
}
// Function to get the sum between indices 'l' and 'r' in the original array
const rangeQuery = (fenwick, l, r) => sumQuery(fenwick, r + 1) - sumQuery(fenwick, l);
// Function to handle queries and updates on the array
const handleQueries = (arr, queries) => {
const fenwick = buildFenwick(arr);
const results = [];
for (const query of queries) {
if (query[0] === 1) {
const l = query[1], r = query[2];
results.push(rangeQuery(fenwick, l, r));
} else if (query[0] === 2) {
const idx = query[1], val = query[2];
const currentVal = isPowerOfTwo(arr[idx]) ? 1 : 0;
const newVal = isPowerOfTwo(val) ? 1 : 0;
update(fenwick, idx + 1, newVal - currentVal);
arr[idx] = val;
}
}
return results;
}
// Driver code
const arr = [12, 11, 16, 2, 32];
const queries = [[1, 0, 2], [2, 4, 24], [1, 1, 4]];
const result = handleQueries(arr, queries);
console.log(result.join(' '));
// This code is contributed by Akshita
Output
[1, 2]
Time Complexity: O((N+Q)*logN) for the initial construction and O(logN) for each update and query, leading to O((N+Q)logN) overall.
Auxilary Space: O(N) for storing the Fenwick Tree.