// C++ implementation of the approach
#include <iostream>
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;
}