Я рекомендую 2 бинарных деревьев поиска (BSTs) - одна будучи карта от a
до b
(отсортированный по a
), другие должны быть отсортированы по b
.
Вторым должен быть пользовательский BST - вам нужно, чтобы каждый узел хранил счетчик количества узлов в поддереве с ним как root - эти подсчеты могут быть обновлены в O (log n), и позволит запросам O (log n) получить k-й наибольший элемент.
При выполнении вставки вы просто сначала посмотрите значение b в первом BST, затем удалите это значение из второго, затем обновите первое и вставьте новое значение во второе.
Для удаления вы просто будете искать значение b в первом BST (и удалить эту пару), а затем удалить это значение из второго.
Все упомянутые операции должны принимать O (log n).
Кэширование
Если вы, к примеру, только собираетесь запросить верхние 10 элементов, можно поддерживать другой BST, содержащий только те 10 элементов (или даже просто необязательно, отсортированный массив, так как есть только 10 элементов), которые мы затем запросим вместо второго BST выше.
При вставке также вставляйте в эту структуру, если значение больше наименьшего, и удалите наименьшее значение.
При удалении нам нужно найти следующее самое большое значение и вставить его в маленький BST. Хотя это также можно сделать лениво - при удалении просто удалите его из этого BST - не заполняйте его до 10 раз. При запросе, если в этом BST есть достаточно элементов, мы можем просто искать его, иначе мы найдем все значения в большом BST, необходимые для заполнения этого BST, а затем мы запрашиваем.
Это приведет к запросу O (1) в наилучшем случае (наихудший вариант O (log n)), в то время как другие операции будут по-прежнему равны O (log n).
Хотя добавленная сложность, вероятно, не стоит того - O (log n) довольно быстро, даже для большого n.
Основываясь на этой идее, мы могли бы только есть этот маленький BST вместе с отображением BST a
в b
- это потребовало бы, что мы проверяем все значения, чтобы найти нужные из них во время выполнения запроса после удаления, так что это будет только действительно выгодно, если нет большого количества изъятий.
@Inertiatic. Приоритетная очередь не будет (эффективно) поддерживать запрос «count-th наибольшее значение» в соответствии с № 3. – Dukeling
@ Dukeling Я, должно быть, неправильно понял вопрос. Edit: Вы правы, я вижу, где я сбежал. Удалить должен искать и удалять этот элемент, который может находиться где угодно в структуре данных. – Inertiatic
Как любые элементы в структуре данных? Если не существует много тысяч, вероятно, что использование упорядоченного вектора ключа и параллельного вектора со значениями и вставка/удаление в них происходит намного быстрее! Если вы можете разумно вешать элементы, например, используя преобразование в 'int', а затем поиск в векторе, вы можете эффективно расширить структуру данных до гораздо большего количества элементов. При обновлении значения вы также должны немедленно сохранить текущее максимальное значение/счетчик, если счетчик больше текущего (нет необходимости искать его). –