Ordered Sets in C++
In C++, ordered sets can be created using special code templates.
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
template<class T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
template<class T> using ordered_multiset = tree<T, null_type, less_equal<T>, rb_tree_tag, tree_order_statistics_node_update>;
Two primary structures are introduced:
ordered_set
maintains sorted unique elements in ascending order usingless
comparison.ordered_multiset
allows duplicates using aless_equal
comparison, preserving the sorted order.
Fucntions
In addition to normal set operations, the ordered set supports:
order_of_key(k)
: Gives the count of elements smaller thank
. — O(log n)find_by_order(k)
: Returns the iterator for thek
th element (usek = 0
for the first element). — O(log n)
Deletion in Multiset
To remove an element in a multiset, you must delete it using iterators:
ss.erase(ss.find_by_order(ss.order_of_key(x)));
Simple Usecase
#include <iostream>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
template<class T> using ordered_multiset = tree<T, null_type, less_equal<T>, rb_tree_tag, tree_order_statistics_node_update>;
int main() {
// Declaration of ordered_multiset as 'ss'
ordered_multiset<int> ss;
// Inserting elements into 'ss'
ss.insert(5);
ss.insert(2);
ss.insert(7);
ss.insert(2); // Allows duplicates
ss.insert(1);
// Displaying elements
cout << "Elements in the ordered_multiset: ";
for (auto it : ss) { // 1 2 2 5 7
cout << it << " ";
}
cout << endl;
// Counting elements less than 5 using order_of_key
cout << "Elements less than 5: " << ss.order_of_key(5) << endl; // 3
// Deleting an element, e.g., deleting value 2
auto it = ss.find_by_order(ss.order_of_key(2)); // Find iterator to the element 2
if (it != ss.end()) {
ss.erase(it); // Erase the found element O(log n)
cout << "Element 2 removed from the ordered_multiset." << endl;
} else {
cout << "Element not found in the ordered_multiset." << endl;
}
return 0;
}
Sorting Descending (or Equal)
This modification greater
allows sorting elements in descending order for set or multiset.
template<class T> using ordered_set = tree<T, null_type, greater<T>, rb_tree_tag, tree_order_statistics_node_update>;
template<class T> using ordered_multiset = tree<T, null_type, greater_equal<T>, rb_tree_tag, tree_order_statistics_node_update>;
Operator Overload
The custom comparison operator is used for handling duplicates within an ordered multiset. It ensures that duplicate elements are retained while maintaining the desired sorting order based on the specified comparison logic.
template<class T>
struct custom_compare {
bool operator()(const T& a, const T& b) const {
if (a == b) return true; // Keep duplicates
return a > b;
}
};
template<class T> using ordered_multiset = tree<T, null_type, custom_compare<T>, rb_tree_tag, tree_order_statistics_node_update>;
You can modify the operator to sort based on anything you want, for example, based on the frequency of each element you would return fr[a] < fr[b];
.
Also, you can check my article on sorting in normal sets/multisets here: Custom Sorting in Normal Sets/Multisets
You can't use ordered_set as ordered_multiset.
Read this
lower_bound
works asupper_bound
, and vice-vercaoh wow... I didn't know that if you replace less with less_equal, you turn a set into a multiset.
it is buggy https://mirror.codeforces.com/blog/entry/95414?#comment-844514
I think
ss.find_by_order(ss.order_of_key(x))
can be replaced withss.lower_bound(x)
Note that in order for lower_bound to work you can use an ordered sait of pairs, where the first number is the value and the second an index or something similar. then when you search you only have to use -INF or INF as the second value in the pair
I guess mentioning
ordered_map
would be relevant here...Alarm! The actual rating of the author is 1287