Hi Codeforcers!
Recently I was trying to solve a query-type problem and after solving the problem I learned something new about C++ that I would like to share. Here's the problem statement:
We have a set that initially contains only a single 0
. This set can contain multiple elements with the same value. We are given $$$Q$$$ queries. There are 3 types of queries:
1- INSERT x : Insert number x to the set
2- DELETE x : Remove number x from the set. It is guaranteed that the number exists in the set
3- MEDIAN : Print median of the numbers in the set. Median of a set of numbers is the middle element after sorting the numbers in the set in non-decreasing order. If the size of the set is a multiple of 2, among the two middle elements, print the left one.
Number of queries won't exceed $$$2 \cdot 10^5$$$.
I will assume that there is only INSERT/MEDIAN queries for convenience.
Naive solutions won't pass the TL. By naive I mean inserting each element in $$$O(1)$$$ and for each median queries sorting the container (probably std::vector) in $$$O(nlogn)$$$. This will lead us to an $$$O(Q\cdot n \cdot logn)$$$ total time complexity which won't pass the time limit with a strong test. I believe there is a solution using some non-STL data structures (e.g. policy base data structures, Fenwick Tree). However, we can solve this problem using std::multiset
so we code less and gain more!
Solution
We take an iterator (std::multiset<T>::iterator
) to the median and we maintain an index which is the 1-based index of the median element in the set.
If we got a MEDIAN query we will immediately print the median by dereferencing the iterator pointing to the median element. If we got an INSERT query we will insert the new element to the set and it is easy to see that by inserting one element the median index will change by at most one. So we can ++
or --
the iterator and keep maintaining the median element. Here's the code: