как удалять за
, и бинпоиском можно находить за
Бинпоиском — в смысле честным или в каком-нибудь дереве хранить? Если честным, то мне не понятно, расскажите, если вам несложно будет.
Сам этот список будем хранить в трёх массивах
Код:
isDelete[0..N+1]
Left[1..N]
Right[1..N]
В массиве isDelete будет хранится 0, если элемент ещё не удалён и 1, если он уже удалён
В массиве Left[i] будет хранится
(i) значение самого правого неудаленного элемента
(ii) либо значение какого-нибудь удаленного элемента
когда какой случай поясню позже.
В массиве
аналогично, но
меняется на
Инициализируется структура так:
Код:
void init()
for(i=0..N+1)
isDelete[i]=0;
Left[i]=i;
Right[i]=i;
isDelete[0]=isDelete[N+1]=1;
Процедура удаления
Код:
void del(i)
isDelete[i]=1;
Left[i] = Left[i-1];
Right[i] = Right[i+1];
Функции findL и findR выглядит так:
Код:
int FindL(i)
return Left[i] = (isDelete[i] == 0) ? i : FindL(Left[i]);
int FindR(i)
return Right[i] = (isDelete[i] == 0) ? i : FindR(Right[i]);
Сперва кажется, что алгоритм должен работать за
ведь рекурсия в худшем случае сделает
самовызовов, однако нетрудно заметить, что
и
суммарно могут быть вызваны за
запросов
раз. Ведь после того, как мы «раскрутили» рекурсию на M шагов вглубь мы, фактически, «сжали»
удаленных элементов в один. Таких «сжатий» не может произойти больше, чем
(так как у нас удаленных элементов всего
). Идея очень похожа на ту, что используется в КМП-алгоритме, а также в DSU. Фактически это и есть «урезанная» версия DSU, так как весовые потенциалы именно в этой задаче нам, по сути, ни к чему.