So far, I know that self-balancing BST like AVL tree and Red Black Tree can do these operations in O(log n) times.
However, to use these structures, we must implement AV
As mentioned in the comments, if you want to maintain a set of integers and you can do a coordinate compression as a preprocessing step (e.g. because your algorithm is offline and knows all the future queries), you can use a binary-indexed tree to support insert/delete/rank/select of numbers in O(log n) per operation. Here's an example in C++:
int tree[N]; // where N is the number of compressed coordinates
const int maxl = floor(log(N)/log(2));
void insert(int i) { // 1 <= i <= N
for (; i <= N; i += i & -i) ++tree[i];
}
void remove(int i) { // 1 <= i <= N
for (; i <= N; i += i & -i) --tree[i];
}
int rank(int i) { // 1 <= i <= N
int sum = 0;
for (; i; i -= i & -i) sum += tree[i];
return sum;
}
int select(int k) { // k is 1-based
int ans = 0, s = 0;
for (int i = maxl; i >= 0; --i) // maxl = largest i s.t. (1<<i) <= N
if (s + tree[ans + (1<<i)] < k) {
ans += 1<<i;
s += tree[ans];
}
return ans+1;
}
The select
function is somewhat magical. It reuses the results from higher bits to compute the prefix sum of ans + (1<<i)
in O(1), which is pretty cool IMHO :) This way it only takes time O(log n), instead of the O(log^2 n) that is easy to achieve using a standard binary search.