Пећински зечеви
Аутор: Александар Вишњић
Текст и тест примери: Александар Вишњић
Анализа решења: Јован Бенгин и Александар Вишњић
Тестирање: Никола Пешић и Јован Бенгин
Први подзадатак
У овим тестовима пећина се може представити као низ, и скок нагоре као прелазак на леви елемент низа.
Најједноставније решење је да се симулирају скокови сваког зеца: кренемо из његове почетне позиције, и сваки пут идемо у најлевљу достижну позицију. Другим речима, ако је $i$-ти зец тернутно на $v$-том месту слева, он ће у следећем кораку отићи на најлевљу позицију са платформом у интервалу $[v-i, v)$ (наравно, ако таква позиција не постоји, онда $i$-ти зец не може да изађе). Ово се лако налази ако имамо низ позиција са платформом, јер онда у том низу можемо бинарном претрагом наћи најмању позицију већу или једнаку $v-i$.
Приметимо да у овако траженом решењу сума висина било која два узастопна скока $i$-тог зеца мора бити већа од $i$ (иначе би се они могли заменити једним скоком), па је и број његових скокова ограничен одозго са $2\lceil \frac{N}{i} \rceil$. Укупан број скокова свих зечева биће ограничен одозго са $2 \sum \limits_{i=1}^n \lceil \frac{N}{i} \rceil$, што је $O(NlogN)$ (сума хармонијског реда), а пошто сваки скок тражимо у временској сложености $O(logN)$, укупна временска сложеност алгоритма биће $O(Nlog^2N)$.
Прва два подзадатка
Уместо низа, користићемо структуру std::set да чувамо позиције соба са платформом. Уместо бинарне претраге можемо онда користити функцију lower_bound, која такође ради у $O(logN)$.
Решење када је $X_i = 0$ за свако $i$
У овом задатку дато је стабло, али без промена стања чворова (соба). Слично као раније, потребно је пронаћи највишу слободну собу од првих неколико соба изнад дате (и то урадити пуно пута). Пошто нема промена, то је могуће урадити бинарним подизањем (binary lifting). Чувамо две sparse табеле, једну са информацијом о $2^k$-том претку, а другу са информацијом колико међу $2^k$ предака (рачунајући сам тај чвор у њих) постоји соба са платформом. Ове информације чувамо за сваки чвор и свако $k = 0,1,2,\ldots,\lfloor \log N \rfloor$.
Решење када је $N \leq 100.000$
Ове тестове пролазе спорије имплементације главног решења.
Главно решење
Присетимо се ранијих закључака. Потребно је $O(N\log N)$ пута наћи прву слободну собу међу $x$ предатака датог чвора. Такође, сада је потребно и подржати $O(N)$ промена соба. Стандардна идеја је употреба тешко-лаке декомпозиције стабла, која је од ове године у програму такмичења. Стабло партиционишемо у ланце на посебан начин. Први ланац креће из корена и наставља у чвор који има највише деце (рачунајући децу на свим дубинама). Понављамо поступак са новим крајем док не дође до листа стабла, чиме смо тада направили цео ланац. Избацивањем овог ланца настају нова подстабла, сваки са својим кореном. Алгоритам се врши за сваки од њих.
На упите одговарамо тако што направимо Фенвиково стабло за сваки ланац, а потом преко шетње нађемо последњи потребан слободан чвор. Промене су подржане поменутом структуром.
За дат почетни чвор, тврдимо да пролазимо кроз $O(\log N)$ ланаца декомпозиције приликом целе шетње (до изласка из пећине, тј. стабла). Нека је $s_p$ величина подстабла чвора $p$. Размотримо алгоритам који, почев од датог чвора, у сваком тренутку подиже тренутни за један изнад њега. Ако променимо ланац декомпозиције, бројач (иницијално $0$) се повећа за $1$. Посматрајмо ситуацију промене. Нека је претходни чвор $u$, наредни $v$, а $w$ чвор у коме се ланац од $v$ наставља. Због начина избора декомпозиције, важи $s_w \geq s_u$. Одавде је јасно $s_v > 2\cdot s_u$. Дакле, $s$-вредност тренутног чвора се повећа барем дупло. То се највише деси $O(\log N)$ пута, одакле следи тврдња.
Правилна имплементација доводи до решења сложености $O(N\log ^2 N)$. Комисија тврди да постоји и решење боље сложености. Такмичару остављамо за вежбу да га пронађе.
Алтернативно главно решење
Прво, размотримо алтернативно решење за низ. Постоји другачији начин да нађемо најлевљу слободну позицију у $[v-i, v)$: то је уједно и најлевља позиција $x$ за коју је број слободних позиција од $1$ до $x$ строго већи од броја слободних позиција од $1$ до $v - i - 1$. Упити “број слободних позиција од $1$ до $x$”, као и промене вредности неке позиције, могу се решити сегментним или Фенвиковим стаблом. Најлевља слободна позиција може се поново наћи бинарном претрагом, само што сада на овај начин у $O(logN)$ одговарамо на упит “постоји ли слободна позиција у $[v-i, x]$”. Дакле, укупна временска сложеност овог решења би била $O(Nlog^3N)$.
Ово решење можемо да уопштимо и на стабло, само нам је потребно да можемо да нађемо суму елемената на путу од корена до произвољног чвора.
Размислимо како бисмо могли да то урадимо када не постоје промене. Можемо да прођемо кроз стабло претрагом у дубину из корена, и чувамо променљиву $x$ која представља суму од корена до тренутног чвора. Када уђемо у чвор, додајeмо његову вредност (у овом случају, $1$ ако има платформу, $0$ ако нема) у $x$. Када излазимо из чвора, одузимамо његову вредност од $x$. Оваквим поступком за сваки чвор имамо суму елемената од корена до њега.
Како се овде могу применити промене? Конструишемо низ $b$ величине $2N$ који одговара горенаведеном поступку: када улазимо у чвор, на крај низа додајемо његову вредност, а када излазимо, додајемо минус од те вредности. Нека су $in_v$ и $out_v$ позиције у низу $b$ које одговарају уласку у чвор $v$ и изласку из њега, редом. Тада је сума елемената у стаблу од корена до $v$ заправо сума елемената у низу $b$ од 1 до $in_v$.
Сада се решење за стабло своди на решење за низ, једино што при промени вредности чвора $v$ морамо у низу променити вредности у $in_v$ и $out_v$, што поново можемо урадити сегментним или Фенвиковим стаблом (мада је у овом случају, ради брзине и једноставности, боље користити Фенвиково). Такође, потребно нам је да брзо налазимо $k$-тог родитеља произвољног чвора, што се лако може урадити методом binary lifting.
Временска сложеност овог решења је $O(Nlog^3N)$, мада је у пракси доста брже: делом јер је бинарна претрага углавном ради на мањим скоковима (јер са већим скоковима завршавамо брже), делом јер су операције над Фенвиковим стаблом врло брзе. У сваком случају, константа решења је јако мала, и комисијина имплементација пролази за 2.5s.