// Adapted from https://w...content-available-to-author-only...s.org/wavelet-trees-introduction
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
#include <climits>
using namespace std;
// wavelet tree class
class wavelet_tree {
public:
// Range to elements
int low, high;
// Left and Right child
wavelet_tree* l, *r;
std::vector<int> freq;
// Default constructor
// Array is in range [x, y]
// Indices are in range [from, to]
wavelet_tree(int* from, int* to, int x, int y)
{
// Initialising low and high
low = x, high = y;
// Array is of 0 length
if (from >= to)
return;
// Array is homogenous
// Example : 1 1 1 1 1
if (high == low) {
// Assigning storage to freq array
freq.reserve(to - from + 1);
// Initialising the Freq array
freq.push_back(0);
// Assigning values
for (auto it = from; it != to; it++)
// freq will be increasing as there'll
// be no further sub-tree
freq.push_back(freq.back() + 1);
return;
}
// Computing mid
int mid = (low + high) / 2;
// Lambda function to check if a number
// is less than or equal to mid
auto lessThanMid = [mid](int x) {
return x <= mid;
};
// Assigning storage to freq array
freq.reserve(to - from + 1);
// Initialising the freq array
freq.push_back(0);
// Assigning value to freq array
for (auto it = from; it != to; it++)
// If lessThanMid returns 1(true), we add
// 1 to previous entry. Otherwise, we add 0
// (element goes to right sub-tree)
freq.push_back(freq.back() + lessThanMid(*it));
// std::stable_partition partitions the array w.r.t Mid
auto pivot = std::stable_partition(from, to, lessThanMid);
// Left sub-tree's object
l = new wavelet_tree(from, pivot, low, mid);
// Right sub-tree's object
r = new wavelet_tree(pivot, to, mid + 1, high);
}
// Count of numbers in range[L..R] less than
// or equal to k
int kOrLess(int l, int r, int k)
{
// No elements int range is less than k
if (l > r or k < low)
return 0;
// All elements in the range are less than k
if (high <= k)
return r - l + 1;
// Computing LtCount and RtCount
int LtCount = freq[l - 1];
int RtCount = freq[r];
// Answer is (no. of element <= k) in
// left + (those <= k) in right
return (this->l->kOrLess(LtCount + 1, RtCount, k) +
this->r->kOrLess(l - LtCount, r - RtCount, k));
}
// Count of numbers in range[L..R] less than
// or equal to k
int kOrMore(int l, int r, int k)
{
// No elements int range are greater than k
if (l > r or k > high)
return 0;
// All elements in the range are greater than k
if (low >= k)
return r - l + 1;
// Computing LtCount and RtCount
int LtCount = freq[l - 1];
int RtCount = freq[r];
// Answer is (no. of element <= k) in
// left + (those <= k) in right
return (this->l->kOrMore(LtCount + 1, RtCount, k) +
this->r->kOrMore(l - LtCount, r - RtCount, k));
}
};
// Driver code
int main()
{
int size = 7, high = INT_MIN;
// 1 2 3 4 5 6 7
int arr[] = {1, 2, 3, 2, 4, 3, 1};
int next[size];
std::map<int, int> next_idx;
for (int i=size-1; i>=0; i--){
if (next_idx.find(arr[i]) == next_idx.end())
next[i] = size + 1;
else
next[i] = next_idx[arr[i]];
next_idx[arr[i]] = i + 1;
high = max(high, next[i]);
}
// Object of class wavelet tree
wavelet_tree obj(next, next + size, 1, high);
// Queries are NON-zero-based
//
// 1 2 3 4 5 6 7
// {1, 2, 3, 2, 4, 3, 1};
// query([3, 6]) = 3;
cout << obj.kOrMore(3, 6, 7) << '\n';
// query([1, 4]) = 3;
cout << obj.kOrMore(1, 4, 5) << '\n';
// query([1, 7]) = 4;
cout << obj.kOrMore(1, 7, 8) << '\n';
return 0;
}
Ly8gQWRhcHRlZCBmcm9tIGh0dHBzOi8vdy4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4ucy5vcmcvd2F2ZWxldC10cmVlcy1pbnRyb2R1Y3Rpb24KCiNpbmNsdWRlIDxpb3N0cmVhbT4KI2luY2x1ZGUgPHZlY3Rvcj4KI2luY2x1ZGUgPG1hcD4KI2luY2x1ZGUgPGFsZ29yaXRobT4KI2luY2x1ZGUgPGNsaW1pdHM+CnVzaW5nIG5hbWVzcGFjZSBzdGQ7CgovLyB3YXZlbGV0IHRyZWUgY2xhc3MgCmNsYXNzIHdhdmVsZXRfdHJlZSB7IApwdWJsaWM6IAoJLy8gUmFuZ2UgdG8gZWxlbWVudHMgCglpbnQgbG93LCBoaWdoOyAKCgkvLyBMZWZ0IGFuZCBSaWdodCBjaGlsZCAKCXdhdmVsZXRfdHJlZSogbCwgKnI7IAoKCXN0ZDo6dmVjdG9yPGludD4gZnJlcTsKCgkvLyBEZWZhdWx0IGNvbnN0cnVjdG9yIAoJLy8gQXJyYXkgaXMgaW4gcmFuZ2UgW3gsIHldIAoJLy8gSW5kaWNlcyBhcmUgaW4gcmFuZ2UgW2Zyb20sIHRvXSAKCXdhdmVsZXRfdHJlZShpbnQqIGZyb20sIGludCogdG8sIGludCB4LCBpbnQgeSkgCgl7IAoJCS8vIEluaXRpYWxpc2luZyBsb3cgYW5kIGhpZ2ggCgkJbG93ID0geCwgaGlnaCA9IHk7IAoKCQkvLyBBcnJheSBpcyBvZiAwIGxlbmd0aCAKCQlpZiAoZnJvbSA+PSB0bykgCgkJCXJldHVybjsgCgoJCS8vIEFycmF5IGlzIGhvbW9nZW5vdXMgCgkJLy8gRXhhbXBsZSA6IDEgMSAxIDEgMSAKCQlpZiAoaGlnaCA9PSBsb3cpIHsgCgkJCS8vIEFzc2lnbmluZyBzdG9yYWdlIHRvIGZyZXEgYXJyYXkgCgkJCWZyZXEucmVzZXJ2ZSh0byAtIGZyb20gKyAxKTsgCgoJCQkvLyBJbml0aWFsaXNpbmcgdGhlIEZyZXEgYXJyYXkgCgkJCWZyZXEucHVzaF9iYWNrKDApOyAKCgkJCS8vIEFzc2lnbmluZyB2YWx1ZXMgCgkJCWZvciAoYXV0byBpdCA9IGZyb207IGl0ICE9IHRvOyBpdCsrKSAKCQkJCgkJCQkvLyBmcmVxIHdpbGwgYmUgaW5jcmVhc2luZyBhcyB0aGVyZSdsbCAKCQkJCS8vIGJlIG5vIGZ1cnRoZXIgc3ViLXRyZWUgCgkJCQlmcmVxLnB1c2hfYmFjayhmcmVxLmJhY2soKSArIDEpOyAKCQkJCgkJCXJldHVybjsgCgkJfSAKCgkJLy8gQ29tcHV0aW5nIG1pZCAKCQlpbnQgbWlkID0gKGxvdyArIGhpZ2gpIC8gMjsgCgoJCS8vIExhbWJkYSBmdW5jdGlvbiB0byBjaGVjayBpZiBhIG51bWJlciAKCQkvLyBpcyBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gbWlkIAoJCWF1dG8gbGVzc1RoYW5NaWQgPSBbbWlkXShpbnQgeCkgeyAKCQkJcmV0dXJuIHggPD0gbWlkOyAKCQl9OyAKCgkJLy8gQXNzaWduaW5nIHN0b3JhZ2UgdG8gZnJlcSBhcnJheSAKCQlmcmVxLnJlc2VydmUodG8gLSBmcm9tICsgMSk7IAoKCQkvLyBJbml0aWFsaXNpbmcgdGhlIGZyZXEgYXJyYXkgCgkJZnJlcS5wdXNoX2JhY2soMCk7IAoKCQkvLyBBc3NpZ25pbmcgdmFsdWUgdG8gZnJlcSBhcnJheSAKCQlmb3IgKGF1dG8gaXQgPSBmcm9tOyBpdCAhPSB0bzsgaXQrKykgCgoJCQkvLyBJZiBsZXNzVGhhbk1pZCByZXR1cm5zIDEodHJ1ZSksIHdlIGFkZCAKCQkJLy8gMSB0byBwcmV2aW91cyBlbnRyeS4gT3RoZXJ3aXNlLCB3ZSBhZGQgMCAKCQkJLy8gKGVsZW1lbnQgZ29lcyB0byByaWdodCBzdWItdHJlZSkgCgkJCWZyZXEucHVzaF9iYWNrKGZyZXEuYmFjaygpICsgbGVzc1RoYW5NaWQoKml0KSk7CQkgCgoJCS8vIHN0ZDo6c3RhYmxlX3BhcnRpdGlvbiBwYXJ0aXRpb25zIHRoZSBhcnJheSB3LnIudCBNaWQgCgkJYXV0byBwaXZvdCA9IHN0ZDo6c3RhYmxlX3BhcnRpdGlvbihmcm9tLCB0bywgbGVzc1RoYW5NaWQpOyAKCgkJLy8gTGVmdCBzdWItdHJlZSdzIG9iamVjdCAKCQlsID0gbmV3IHdhdmVsZXRfdHJlZShmcm9tLCBwaXZvdCwgbG93LCBtaWQpOyAKCgkJLy8gUmlnaHQgc3ViLXRyZWUncyBvYmplY3QgCgkJciA9IG5ldyB3YXZlbGV0X3RyZWUocGl2b3QsIHRvLCBtaWQgKyAxLCBoaWdoKTsgCgl9IAoKCS8vIENvdW50IG9mIG51bWJlcnMgaW4gcmFuZ2VbTC4uUl0gbGVzcyB0aGFuIAoJLy8gb3IgZXF1YWwgdG8gayAKCWludCBrT3JMZXNzKGludCBsLCBpbnQgciwgaW50IGspIAoJeyAKCQkvLyBObyBlbGVtZW50cyBpbnQgcmFuZ2UgaXMgbGVzcyB0aGFuIGsgCgkJaWYgKGwgPiByIG9yIGsgPCBsb3cpIAoJCQlyZXR1cm4gMDsgCgoJCS8vIEFsbCBlbGVtZW50cyBpbiB0aGUgcmFuZ2UgYXJlIGxlc3MgdGhhbiBrIAoJCWlmIChoaWdoIDw9IGspIAoJCQlyZXR1cm4gciAtIGwgKyAxOyAKCgkJLy8gQ29tcHV0aW5nIEx0Q291bnQgYW5kIFJ0Q291bnQgCgkJaW50IEx0Q291bnQgPSBmcmVxW2wgLSAxXTsgCgkJaW50IFJ0Q291bnQgPSBmcmVxW3JdOyAKCgkJLy8gQW5zd2VyIGlzIChuby4gb2YgZWxlbWVudCA8PSBrKSBpbiAKCQkvLyBsZWZ0ICsgKHRob3NlIDw9IGspIGluIHJpZ2h0IAoJCXJldHVybiAodGhpcy0+bC0+a09yTGVzcyhMdENvdW50ICsgMSwgUnRDb3VudCwgaykgKyAKCQkJdGhpcy0+ci0+a09yTGVzcyhsIC0gTHRDb3VudCwgciAtIFJ0Q291bnQsIGspKTsgCgl9IAoKCS8vIENvdW50IG9mIG51bWJlcnMgaW4gcmFuZ2VbTC4uUl0gbGVzcyB0aGFuIAoJLy8gb3IgZXF1YWwgdG8gayAKCWludCBrT3JNb3JlKGludCBsLCBpbnQgciwgaW50IGspIAoJeyAKCQkvLyBObyBlbGVtZW50cyBpbnQgcmFuZ2UgYXJlIGdyZWF0ZXIgdGhhbiBrIAoJCWlmIChsID4gciBvciBrID4gaGlnaCkgCgkJCXJldHVybiAwOyAKCgkJLy8gQWxsIGVsZW1lbnRzIGluIHRoZSByYW5nZSBhcmUgZ3JlYXRlciB0aGFuIGsgCgkJaWYgKGxvdyA+PSBrKSAKCQkJcmV0dXJuIHIgLSBsICsgMTsgCgoJCS8vIENvbXB1dGluZyBMdENvdW50IGFuZCBSdENvdW50IAoJCWludCBMdENvdW50ID0gZnJlcVtsIC0gMV07IAoJCWludCBSdENvdW50ID0gZnJlcVtyXTsgCgoJCS8vIEFuc3dlciBpcyAobm8uIG9mIGVsZW1lbnQgPD0gaykgaW4gCgkJLy8gbGVmdCArICh0aG9zZSA8PSBrKSBpbiByaWdodCAKCQlyZXR1cm4gKHRoaXMtPmwtPmtPck1vcmUoTHRDb3VudCArIDEsIFJ0Q291bnQsIGspICsgCgkJCXRoaXMtPnItPmtPck1vcmUobCAtIEx0Q291bnQsIHIgLSBSdENvdW50LCBrKSk7IAoJfQoKfTsgCgovLyBEcml2ZXIgY29kZSAKaW50IG1haW4oKSAKeyAKCWludCBzaXplID0gNywgaGlnaCA9IElOVF9NSU47CiAgICAgICAgICAgICAgICAgLy8gMSAgMiAgMyAgNCAgNSAgNiAgNwoJaW50IGFycltdID0gezEsIDIsIDMsIDIsIDQsIDMsIDF9OwoJaW50IG5leHRbc2l6ZV07CglzdGQ6Om1hcDxpbnQsIGludD4gbmV4dF9pZHg7CgkKCWZvciAoaW50IGk9c2l6ZS0xOyBpPj0wOyBpLS0pewoJCWlmIChuZXh0X2lkeC5maW5kKGFycltpXSkgPT0gbmV4dF9pZHguZW5kKCkpCgkJCW5leHRbaV0gPSBzaXplICsgMTsKCQllbHNlCgkJCW5leHRbaV0gPSBuZXh0X2lkeFthcnJbaV1dOwoJCW5leHRfaWR4W2FycltpXV0gPSBpICsgMTsKCQloaWdoID0gbWF4KGhpZ2gsIG5leHRbaV0pOwoJfSAKCgkvLyBPYmplY3Qgb2YgY2xhc3Mgd2F2ZWxldCB0cmVlIAoJd2F2ZWxldF90cmVlIG9iaihuZXh0LCBuZXh0ICsgc2l6ZSwgMSwgaGlnaCk7CgoJLy8gUXVlcmllcyBhcmUgTk9OLXplcm8tYmFzZWQKCS8vCgkvLyAgMSAgMiAgMyAgNCAgNSAgNiAgNwoJLy8gezEsIDIsIDMsIDIsIDQsIDMsIDF9OwoJLy8gcXVlcnkoWzMsIDZdKSA9IDM7Cgljb3V0IDw8IG9iai5rT3JNb3JlKDMsIDYsIDcpIDw8ICdcbic7CgkvLyBxdWVyeShbMSwgNF0pID0gMzsKCWNvdXQgPDwgb2JqLmtPck1vcmUoMSwgNCwgNSkgPDwgJ1xuJzsKCS8vIHF1ZXJ5KFsxLCA3XSkgPSA0OwoJY291dCA8PCBvYmoua09yTW9yZSgxLCA3LCA4KSA8PCAnXG4nOwoKCXJldHVybiAwOyAKfSAK