Похоже, вы могли бы просто использовать сбалансированное двоичное дерево всех граничных времен.
Например, представьте {(1,4), (8,10), (12,15)} как дерево, содержащее 1, 4, 8, 10, 12 и 15.
Каждый узел должен сказать, начало или конец интервала. Так:
8 (start)
/ \
1 (start) 12 (start)
\ / \
4 (end) 10 (end) 15 (end)
(Здесь все "конечные" узлы случайно оказались внизу.)
Тогда я думаю, что вы можете выполнять все свои операции за время O (log n). Чтобы добавить интервал:
Найдите время начала. Если он уже находится в дереве в качестве времени начала, вы можете оставить его там. Если он уже находится в дереве в качестве конечного времени, вы захотите его удалить. Если его нет в дереве и он не падает в течение существующего интервала, вы захотите добавить его. В противном случае вы не захотите его добавлять.
Найдите время остановки, используя тот же метод, чтобы узнать, нужно ли вам его добавить, удалить или нет.
Теперь вы просто хотите добавить или удалить вышеупомянутые узлы запуска и остановки и в то же время удалить все существующие узлы между ними. Для этого вам нужно только перестроить узлы дерева в этих двух местах или прямо над ними. Если высота дерева равна O (log n), что вы можете гарантировать, используя сбалансированное дерево, это займет время O (log n).
(Отказ от ответственности: если вы используете C ++ и выполняете явное управление памятью, вы можете в конечном итоге освободить больше, чем O (log n) частей памяти, когда вы это сделаете, но на самом деле время, необходимое для освобождения узла, должно быть оплачено кем-либо добавил, я думаю.)
Удаление интервала во многом то же самое.
Проверить точку или интервал очень просто.
Нахождение первого пробела хотя бы заданного размера через заданное время также может быть выполнено за O (журнал n), если вы также кэшируете еще две части информации на узел:
В каждом начальном узле (кроме крайнего левого) размер зазора сразу слева.
В каждом узле - размер наибольшего разрыва, который появляется в этом поддереве.
Чтобы найти первый пробел заданного размера, который появляется через заданное время, сначала найдите это время в дереве. Затем идите вверх, пока не дойдете до узла, который утверждает, что содержит достаточно большой промежуток. Если вы подошли справа, вы знаете, что эта пропасть находится слева, поэтому вы игнорируете ее и продолжаете идти вверх. В противном случае вы пришли слева. Если узел является начальным, проверьте, достаточно ли велик зазор слева от него. Если так, то все готово. В противном случае достаточно большой зазор должен быть где-то справа. Пройдите вправо и продолжайте идти, пока не найдете брешь. Опять же, поскольку высота дерева равна O (log n), пройти его три раза (вниз, вверх и, возможно, снова вниз) будет O (log n).
person
Jason Orendorff
schedule
31.12.2009