给定一个由N 个整数组成的数组arr[]和一个由以下两种类型的查询组成的二维数组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),来构建一个段树 类似于 sum 段树,每个节点存储元素的数量,在它的子树中只有一个位:
- 如果ss == se, tree[s[i]] = check (arr[ss] )
- 否则,遍历左子树和右子树。
- 现在,将当前节点更新为tree[si] = tree[2 * si + 1]+ tree[2 * si + 2]。
- 定义一个函数,比如update( ss, se, si, X, V) ,指向更新数组arr[]中的一个值:
- 如果当前节点是叶节点,即ss == se则更新tree[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 query(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 }类型的查询,打印query(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)
如果您想与行业专家一起参加直播课程,请参阅Geeks Classes Live