📌  相关文章
📜  从具有单个设置位的给定范围计算数组元素的查询

📅  最后修改于: 2021-09-07 02:25:02             🧑  作者: Mango

给定一个由N 个整数组成的数组arr[]和一个由以下两种类型的查询组成的二维数组Q[][]

  • 1 LR:打印范围[L, R]中只有一个设置位的数字计数。
  • 2 XV:V更新第X索引处的数组元素。

例子:

朴素的方法:最简单的方法是在每个查询和每个元素的索引范围[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