📌  相关文章
📜  具有更新查询的二进制数组中的第k个设置位的索引

📅  最后修改于: 2021-04-17 11:16:17             🧑  作者: Mango

给定以下类型的二进制数组arr []q查询:

  1. k:在数组中找到第k设置位的索引,即k th 1
  2. (x,y):更新arr [x] = y ,其中y可以为01

例子:

方法:一个简单的解决方案是运行一个从0n – 1的循环并找到第k1 。要更新值,只需执行arr [i] = x即可。第一次操作花费O(n)时间,第二次操作花费O(1)时间。

另一个解决方案是创建另一个数组,并将每个1的索引存储在此数组的i索引处。现在可以在O(1)时间中计算K th 1的索引,但是现在更新操作需要O(n)时间。如果查询操作的数量很大且更新很少,则此方法效果很好。

但是,如果查询和更新的数量相等怎么办?我们可以使用段树O(log n)时间内执行这两项操作,并在O(Logn)时间内进行两项操作。

下面是上述方法的实现:

C++
// C++ implementation of the approach
#include 
using namespace std;
  
// Function to build the tree
void buildTree(int* tree, int* a, int s, int e, int idx)
{
    // s = starting index
    // e = ending index
    // a = array storing binary string of numbers
    // idx = starting index = 1, for recurring the tree
    if (s == e) {
  
        // store each element value at the
        // leaf node
        tree[idx] = a[s];
        return;
    }
  
    int mid = (s + e) / 2;
  
    // Recurring in two sub portions (left, right)
    // to build the segment tree
  
    // Calling for the left sub portion
    buildTree(tree, a, s, mid, 2 * idx);
  
    // Calling for the right sub portion
    buildTree(tree, a, mid + 1, e, 2 * idx + 1);
  
    // Summing up the number of one's
    tree[idx] = tree[2 * idx] + tree[2 * idx + 1];
  
    return;
}
  
// Function to return the index of the query
int queryTree(int* tree, int s, int e, int k, int idx)
{
    // s = starting index
    // e = ending index
    // k = searching for kth bit
    // idx = starting index = 1, for recurring the tree
  
    // k > number of 1's in a binary string
    if (k > tree[idx])
        return -1;
  
    // leaf node at which kth 1 is stored
    if (s == e)
        return s;
    int mid = (s + e) / 2;
  
    // If left sub-tree contains more or equal 1's
    // than required kth 1
    if (tree[2 * idx] >= k)
        return queryTree(tree, s, mid, k, 2 * idx);
  
    // If left sub-tree contains less 1's than
    // required kth 1 then recur in the right sub-tree
    else
        return queryTree(tree, mid + 1, e, k - tree[2 * idx], 2 * idx + 1);
}
  
// Function to perform the update query
void updateTree(int* tree, int s, int e, int i, int change, int idx)
{
    // s = starting index
    // e = ending index
    // i = index at which change is to be done
    // change = new changed bit
    // idx = starting index = 1, for recurring the tree
  
    // Out of bounds request
    if (i < s || i > e) {
        cout << "error";
        return;
    }
  
    // Leaf node of the required index i
    if (s == e) {
  
        // Replacing the node value with
        // the new changed value
        tree[idx] = change;
        return;
    }
  
    int mid = (s + e) / 2;
  
    // If the index i lies in the left sub-tree
    if (i >= s && i <= mid)
        updateTree(tree, s, mid, i, change, 2 * idx);
  
    // If the index i lies in the right sub-tree
    else
        updateTree(tree, mid + 1, e, i, change, 2 * idx + 1);
  
    // Merging both left and right sub-trees
    tree[idx] = tree[2 * idx] + tree[2 * idx + 1];
    return;
}
  
// Function to perform queries
void queries(int* tree, int* a, int q, int p, int k, int change, int n)
{
    int s = 0, e = n - 1, idx = 1;
    if (q == 1) {
        // q = 1 update, p = index at which change
        // is to be done, change = new bit
        a[p] = change;
        updateTree(tree, s, e, p, change, idx);
        cout << "Array after updation:\n";
        for (int i = 0; i < n; i++)
            cout << a[i] << " ";
        cout << "\n";
    }
    else {
        // q = 0, print kth bit
        cout << "Index of " << k << "th set bit: "
             << queryTree(tree, s, e, k, idx) << "\n";
    }
}
  
// Driver code
int main()
{
    int a[] = { 1, 0, 1, 0, 0, 1, 1, 1 };
    int n = sizeof(a) / sizeof(int);
  
    // Declaring & initializing the tree with
    // maximum possible size of the segment tree
    // and each value initially as 0
    int* tree = new int[4 * n + 1];
    for (int i = 0; i < 4 * n + 1; ++i) {
        tree[i] = 0;
    }
  
    // s and e are the starting and ending
    // indices respectively
    int s = 0, e = n - 1, idx = 1;
  
    // Build the segment tree
    buildTree(tree, a, s, e, idx);
  
    // Find index of kth set bit
    int q = 0, p = 0, change = 0, k = 4;
    queries(tree, a, q, p, k, change, n);
  
    // Update query
    q = 1, p = 5, change = 0;
    queries(tree, a, q, p, k, change, n);
  
    return 0;
}


Java
// Java implementation of the approach
import java.io.*;
import java.util.*;
  
class GFG 
{
  
    // Function to build the tree
    static void buildTree(int[] tree, int[] a, 
                       int s, int e, int idx) 
    {
  
        // s = starting index
        // e = ending index
        // a = array storing binary string of numbers
        // idx = starting index = 1, for recurring the tree
        if (s == e) 
        {
  
            // store each element value at the
            // leaf node
            tree[idx] = a[s];
            return;
        }
  
        int mid = (s + e) / 2;
  
        // Recurring in two sub portions (left, right)
        // to build the segment tree
  
        // Calling for the left sub portion
        buildTree(tree, a, s, mid, 2 * idx);
  
        // Calling for the right sub portion
        buildTree(tree, a, mid + 1, e, 2 * idx + 1);
  
        // Summing up the number of one's
        tree[idx] = tree[2 * idx] + tree[2 * idx + 1];
  
        return;
    }
  
    // Function to return the index of the query
    static int queryTree(int[] tree, int s, 
                        int e, int k, int idx) 
    {
  
        // s = starting index
        // e = ending index
        // k = searching for kth bit
        // idx = starting index = 1, for recurring the tree
  
        // k > number of 1's in a binary string
        if (k > tree[idx])
            return -1;
  
        // leaf node at which kth 1 is stored
        if (s == e)
            return s;
        int mid = (s + e) / 2;
  
        // If left sub-tree contains more or equal 1's
        // than required kth 1
        if (tree[2 * idx] >= k)
            return queryTree(tree, s, mid, k, 2 * idx);
  
        // If left sub-tree contains less 1's than
        // required kth 1 then recur in the right sub-tree
        else
            return queryTree(tree, mid + 1, e, k - tree[2 * idx],
                                                    2 * idx + 1);
    }
  
    // Function to perform the update query
    static void updateTree(int[] tree, int s, int e, 
                            int i, int change, int idx)
    {
  
        // s = starting index
        // e = ending index
        // i = index at which change is to be done
        // change = new changed bit
        // idx = starting index = 1, for recurring the tree
  
        // Out of bounds request
        if (i < s || i > e)
        {
            System.out.println("Error");
            return;
        }
  
        // Leaf node of the required index i
        if (s == e)
        {
  
            // Replacing the node value with
            // the new changed value
            tree[idx] = change;
            return;
        }
  
        int mid = (s + e) / 2;
  
        // If the index i lies in the left sub-tree
        if (i >= s && i <= mid)
            updateTree(tree, s, mid, i, change, 2 * idx);
  
        // If the index i lies in the right sub-tree
        else
            updateTree(tree, mid + 1, e, i, change, 2 * idx + 1);
  
        // Merging both left and right sub-trees
        tree[idx] = tree[2 * idx] + tree[2 * idx + 1];
        return;
    }
  
    // Function to perform queries
    static void queries(int[] tree, int[] a, int q, int p, 
                                int k, int change, int n) 
    {
        int s = 0, e = n - 1, idx = 1;
        if (q == 1) 
        {
  
            // q = 1 update, p = index at which change
            // is to be done, change = new bit
            a[p] = change;
            updateTree(tree, s, e, p, change, idx);
            System.out.println("Array after updation:");
            for (int i = 0; i < n; i++)
                System.out.print(a[i] + " ");
            System.out.println();
        } 
        else 
        {
  
            // q = 0, print kth bit
            System.out.printf("Index of %dth set bit: %d\n", 
                                k, queryTree(tree, s, e, k, idx));
        }
    }
  
    // Driver Code
    public static void main(String[] args) 
    {
        int[] a = { 1, 0, 1, 0, 0, 1, 1, 1 };
        int n = a.length;
  
        // Declaring & initializing the tree with
        // maximum possible size of the segment tree
        // and each value initially as 0
        int[] tree = new int[4 * n + 1];
        for (int i = 0; i < 4 * n + 1; ++i) 
        {
            tree[i] = 0;
        }
  
        // s and e are the starting and ending
        // indices respectively
        int s = 0, e = n - 1, idx = 1;
  
        // Build the segment tree
        buildTree(tree, a, s, e, idx);
  
        // Find index of kth set bit
        int q = 0, p = 0, change = 0, k = 4;
        queries(tree, a, q, p, k, change, n);
  
        // Update query
        q = 1;
        p = 5;
        change = 0;
        queries(tree, a, q, p, k, change, n);
    }
}
  
// This code is contributed by
// sanjeev2552


Python3
# Python3 implementation of the approach
  
# Function to build the tree
def buildTree(tree: list, a: list, 
                s: int, e: int, idx: int):
  
    # s = starting index
    # e = ending index
    # a = array storing binary string of numbers
    # idx = starting index = 1, for recurring the tree
    if s == e:
  
        # store each element value at the
        # leaf node
        tree[idx] = a[s]
        return
  
    mid = (s + e) // 2
  
    # Recurring in two sub portions (left, right)
    # to build the segment tree
  
    # Calling for the left sub portion
    buildTree(tree, a, s, mid, 2 * idx)
  
    # Calling for the right sub portion
    buildTree(tree, a, mid + 1, e, 2 * idx + 1)
  
    # Summing up the number of one's
    tree[idx] = tree[2 * idx] + tree[2 * idx + 1]
  
    return
  
# Function to return the index of the query
def queryTree(tree: list, s: int, e: int, 
            k: int, idx: int) -> int:
  
    # s = starting index
    # e = ending index
    # k = searching for kth bit
    # idx = starting index = 1, for recurring the tree
  
    # k > number of 1's in a binary string
    if k > tree[idx]:
        return -1
  
    # leaf node at which kth 1 is stored
    if s == e:
        return s
    mid = (s + e) // 2
  
    # If left sub-tree contains more or equal 1's
    # than required kth 1
    if tree[2 * idx] >= k:
        return queryTree(tree, s, mid, k, 2 * idx)
  
    # If left sub-tree contains less 1's than
    # required kth 1 then recur in the right sub-tree
    else:
        return queryTree(tree, mid + 1, e, 
                    k - tree[2 * idx], 2 * idx + 1)
  
# Function to perform the update query
def updateTree(tree: list, s: int, e: int, 
                i: int, change: int, idx: int):
  
    # s = starting index
    # e = ending index
    # i = index at which change is to be done
    # change = new changed bit
    # idx = starting index = 1, for recurring the tree
  
    # Out of bounds request
    if i < s or i > e:
        print("error")
        return
  
    # Leaf node of the required index i
    if s == e:
  
        # Replacing the node value with
        # the new changed value
        tree[idx] = change
        return
  
    mid = (s + e) // 2
  
    # If the index i lies in the left sub-tree
    if i >= s and i <= mid:
        updateTree(tree, s, mid, i, change, 2 * idx)
  
    # If the index i lies in the right sub-tree
    else:
        updateTree(tree, mid + 1, e, i, change, 2 * idx + 1)
  
    # Merging both left and right sub-trees
    tree[idx] = tree[2 * idx] + tree[2 * idx + 1]
    return
  
# Function to perform queries
def queries(tree: list, a: list, q: int, p: int, 
            k: int, change: int, n: int):
    s = 0
    e = n - 1
    idx = 1
    if q == 1:
  
        # q = 1 update, p = index at which change
        # is to be done, change = new bit
        a[p] = change
        updateTree(tree, s, e, p, change, idx)
        print("Array after updation:")
        for i in range(n):
            print(a[i], end=" ")
        print()
    else:
  
        # q = 0, print kth bit
        print("Index of %dth set bit: %d" % (k, 
                queryTree(tree, s, e, k, idx)))
  
# Driver Code
if __name__ == "__main__":
    a = [1, 0, 1, 0, 0, 1, 1, 1]
    n = len(a)
  
    # Declaring & initializing the tree with
    # maximum possible size of the segment tree
    # and each value initially as 0
    tree = [0] * (4 * n + 1)
  
    # s and e are the starting and ending
    # indices respectively
    s = 0
    e = n - 1
    idx = 1
  
    # Build the segment tree
    buildTree(tree, a, s, e, idx)
  
    # Find index of kth set bit
    q = 0
    p = 0
    change = 0
    k = 4
    queries(tree, a, q, p, k, change, n)
  
    # Update query
    q = 1
    p = 5
    change = 0
    queries(tree, a, q, p, k, change, n)
  
# This code is contributed by
# sanjeev2552


C#
// C# implementation of the approach
using System;
  
class GFG 
{
  
    // Function to build the tree
    static void buildTree(int[] tree, int[] a, 
                        int s, int e, int idx) 
    {
  
        // s = starting index
        // e = ending index
        // a = array storing binary string of numbers
        // idx = starting index = 1, for recurring the tree
        if (s == e) 
        {
  
            // store each element value at the
            // leaf node
            tree[idx] = a[s];
            return;
        }
  
        int mid = (s + e) / 2;
  
        // Recurring in two sub portions (left, right)
        // to build the segment tree
  
        // Calling for the left sub portion
        buildTree(tree, a, s, mid, 2 * idx);
  
        // Calling for the right sub portion
        buildTree(tree, a, mid + 1, e, 2 * idx + 1);
  
        // Summing up the number of one's
        tree[idx] = tree[2 * idx] + tree[2 * idx + 1];
  
        return;
    }
  
    // Function to return the index of the query
    static int queryTree(int[] tree, int s, 
                        int e, int k, int idx) 
    {
  
        // s = starting index
        // e = ending index
        // k = searching for kth bit
        // idx = starting index = 1, for recurring the tree
  
        // k > number of 1's in a binary string
        if (k > tree[idx])
            return -1;
  
        // leaf node at which kth 1 is stored
        if (s == e)
            return s;
        int mid = (s + e) / 2;
  
        // If left sub-tree contains more or equal 1's
        // than required kth 1
        if (tree[2 * idx] >= k)
            return queryTree(tree, s, mid, k, 2 * idx);
  
        // If left sub-tree contains less 1's than
        // required kth 1 then recur in the right sub-tree
        else
            return queryTree(tree, mid + 1, 
                            e, k - tree[2 * idx],
                            2 * idx + 1);
    }
  
    // Function to perform the update query
    static void updateTree(int[] tree, int s, int e, 
                            int i, int change, int idx)
    {
  
        // s = starting index
        // e = ending index
        // i = index at which change is to be done
        // change = new changed bit
        // idx = starting index = 1, for recurring the tree
  
        // Out of bounds request
        if (i < s || i > e)
        {
            Console.WriteLine("Error");
            return;
        }
  
        // Leaf node of the required index i
        if (s == e)
        {
  
            // Replacing the node value with
            // the new changed value
            tree[idx] = change;
            return;
        }
  
        int mid = (s + e) / 2;
  
        // If the index i lies in the left sub-tree
        if (i >= s && i <= mid)
            updateTree(tree, s, mid, i, 
                        change, 2 * idx);
  
        // If the index i lies in the right sub-tree
        else
            updateTree(tree, mid + 1, e, i,
                       change, 2 * idx + 1);
  
        // Merging both left and right sub-trees
        tree[idx] = tree[2 * idx] + 
                    tree[2 * idx + 1];
        return;
    }
  
    // Function to perform queries
    static void queries(int[] tree, int[] a, int q, int p, 
                                int k, int change, int n) 
    {
        int s = 0, e = n - 1, idx = 1;
        if (q == 1) 
        {
  
            // q = 1 update, p = index at which change
            // is to be done, change = new bit
            a[p] = change;
            updateTree(tree, s, e, p, change, idx);
            Console.WriteLine("Array after updation:");
            for (int i = 0; i < n; i++)
                Console.Write(a[i] + " ");
            Console.WriteLine();
        } 
        else
        {
  
            // q = 0, print kth bit
            Console.Write("Index of {0}th set bit: {1}\n", 
                            k, queryTree(tree, s, e, k, idx));
        }
    }
  
    // Driver Code
    public static void Main(String[] args) 
    {
        int[] a = { 1, 0, 1, 0, 0, 1, 1, 1 };
        int n = a.Length;
  
        // Declaring & initializing the tree with
        // maximum possible size of the segment tree
        // and each value initially as 0
        int[] tree = new int[4 * n + 1];
        for (int i = 0; i < 4 * n + 1; ++i) 
        {
            tree[i] = 0;
        }
  
        // s and e are the starting and ending
        // indices respectively
        int s = 0, e = n - 1, idx = 1;
  
        // Build the segment tree
        buildTree(tree, a, s, e, idx);
  
        // Find index of kth set bit
        int q = 0, p = 0, change = 0, k = 4;
        queries(tree, a, q, p, k, change, n);
  
        // Update query
        q = 1;
        p = 5;
        change = 0;
        queries(tree, a, q, p, k, change, n);
    }
}
  
// This code is contributed by Rajput-Ji


输出:
Index of 4th set bit: 6
Array after updation:
1 0 1 0 0 0 1 1