const int *
int const *
int * const
int const * const
const int * function (const arg) const
return void(l = r = 0);
VERSION 2.0 RELEASED! Now with 100% less memory leaks or MLE verdicts. Project moved from Github.
The following text is for version 1.0.
Based on the e-maxx implementation and other stuff I found online, I pieced together a powerful treap. It can be used as a set<>, array, segment tree or (within limits) all of them at once.
Consider a set<> represented as a sorted array of distinct elements. You can insert/remove elements just like in a set<>. You can also find the index of any element in this array, remove an element by index — or insert an element at an index, but that will probably break the sortedness and you can't use the operations which rely on it anymore (you can still insert/remove elements by index). As long as the array is sorted, you can query lower bound / upper bound of any element, given as a pair (element, index).
Next, you can reverse a range, add to a range and query range sums; this will work all the time, but range addition can and reversing will break the sortedness. You can implement your own queries (like min/max) or combined range updates (paint+add) like in a segment tree. Since we need lazy propagation, everything is immutable (you can work around it e.g. with erase/insert) and I decided not to bother with iterators.
I took special care with randomisation. It uses testlib random_t and if equal priorities are detected (at insert), they're all regenerated, but it shouldn't happen with reasonably small data — the priorities are 60-bit, which is far above the Birthday Paradox threshold for just about anything.
The DS is templated over some type T, which has to be comparable and support addition / subtraction / multiplication by int (like a vector space in math).
It supports the following operations, all online in (with N being the current number of elements, ofc):
function | action | returns |
insert(element) | inserts element into a set | bool(was it inserted?) |
insert_pos(index, element) | inserts element at index | void |
erase(element) | removes element from a set | bool(was it removed?) |
erase_pos(index) | removes element at index | void |
get_index(element) | finds the element's index, size() if non-existent | int in [0..size()] |
[index] | finds the element at index | T (not T&) |
lower_bound(element) | finds the lower_bound() of that element, with index | pair<T,int> |
upper_bound(element) | the same with upper_bound() | pair<T,int> |
shift(left,right,element) | add element to everything in the range [left,right] | void |
reverse(left,right) | reverse the range [left,right] | void |
sum(left,right) | find the sum of the range [left,right] | T |
Also, there's the usual empty()
, size()
, is_sorted()
(returns true if the sortedness hasn't been broken yet) and srand()
, which lets you choose your seed if you don't want the testlib default.
I compared it with STL set<> on a million insert/erase/lower_bound operations; the treapset is ~3-4 times slower (which makes sense, since the structure supports many more operations). I also tested it on a million insert_pos/get_index/shift/reverse/sum operations; it took ~4 seconds locally. It seems to work...
Some questions. What happens if there is no element at the position? (erase_pos). Similarly, what happens if you insert_pos at position 273472348, or something? Does it default to the size of the set?
nothing, if(pos >= s.size()) return;
Wow! This is so cool
I have got MLE here https://mirror.codeforces.com/contest/641/submission/189834153
all my code is
Maybe not all bugs were fixed or am I doing something wrong?
Didn't check your code yet but not all bugs were fixed. I know about it from some older submission but didn't get to it.
205220953 Took me a while to get to it, but here it works. What happened: there are memory leaks I'm just fixing, but you ran out of memory for an unrelated reason.
The real problem isn't a bug, it's by design — you have to choose RNG properly since the default became "allocate your own RNG" and that's a big object, which isn't a problem unless you're making potentially 200,000 of them like here. The non-default (but somewhat recommended) alternative is choosing your own RNG, in this case one for the whole program is sufficient:
I'll have to put proper info in the readme.