std::set cannot answer “what is the -th smallest?” or “how many elements are less than ?”. GNU C++ ships a policy-based data structure that can, in .

Setup

#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>;

The two extra operations

ordered_set<int> s;
s.insert(5); s.insert(1); s.insert(9);
 
*s.find_by_order(0);        // 1  — the k-th smallest (0-indexed)
s.order_of_key(9);          // 2  — how many elements are strictly less than 9

Everything std::set offers still works: insert, erase, lower_bound, iteration.

Making a multiset

tree with less<T> rejects duplicates. Two workarounds:

1. Pair the value with a unique tiebreaker (recommended):

ordered_set<pair<int,int>> s;
int timer_ = 0;
s.insert({value, timer_++});
// count of elements < v:
s.order_of_key({v, -1});
// erase one occurrence:
s.erase(s.lower_bound({value, -1}));

2. Use less_equal<T> as the comparator. This allows duplicates but breaks find and erase(value) — they rely on a strict weak ordering. Only use it if you never need those, and prefer option 1.

Portability

GCC only

PBDS is a libstdc++ extension. It works on Codeforces, AtCoder and most judges, but not on MSVC or libc++ (Clang on macOS). If portability matters, use one of the alternatives below.

The alternatives

ApproachPreprocessingQueryNotes
PBDS treeshortest code
BIT over compressed valuesfaster, portable; needs values known in advance
BIT with binary lifting descent-th smallest in one descent, no extra log
Segment tree over valuessupports more aggregates
Treap with subtree sizesfully customisable
Sqrt decomposition over valuessimplest to reason about

BIT with -th smallest descent

When the value range is known, this is the fastest option — one descent, no binary search on top:

int kth(int k) {                     // k-th smallest, 1-indexed
    int pos = 0;
    for (int pw = 1 << LOG; pw; pw >>= 1)
        if (pos + pw <= n && bit[pos + pw] < k) { pos += pw; k -= bit[pos]; }
    return pos + 1;
}

What ordered sets solve

ProblemMethod
Count inversionsinsert right to left, order_of_key
-th smallest in a growing setfind_by_order
Rank of an elementorder_of_key
Count elements in order_of_key(r+1) - order_of_key(l)
Running medianfind_by_order(size()/2)
Count pairs with and inversions
Sliding window -th smallestinsert and erase as the window moves

Other PBDS containers

gp_hash_table is a fast open-addressing hash map — typically 3-5× faster than unordered_map and, with a custom hash, resistant to anti-hash tests:

#include <ext/pb_ds/assoc_container.hpp>
gp_hash_table<long long, int> h;

Add a randomised hash (splitmix64 with a time-based seed) if the keys are adversarial; the default hash for integers is the identity, which is trivially hackable.

See also: Fenwick Tree · Balanced BSTs · STL Containers