Opis
BOI 2016
Bosses
Park
Spiral
Cities
Maze
Swap
CEOI 2017
Skierowanie dróg
Pewny zakład
Pułapka Mariusza
Budujemy mosty
Pościg Mariusza
Palindromiczny podział
BOI 2018
Miłosny wielokąt
Marsjańskie DNA
Problemy dżdżownicy
Prąd przemienny
Genetyka
Ścieżki
BOI 2019
Flash Memory
Nautilus
Alpine Valley
Tom's Kitchen
Necklace
Olympiads
BOI 2020
Kolory
Mieszanki
Joker
Graf
Wioska
Wirusy
CEOI 2020
Fajny płot
Drogi
Star Trek
Napój Wielkiej Potęgi
Wiosenne porządki
Szachowa gorączka

Wiosenne porządki

Dla dowolnego drzewa definiujemy koszt wyczyszczenia tego drzewa jako najmniejszą sumę odległości między odpowiednio sparowanymi liśćmi, gdzie każdy liść ma należeć do dokładniej jednej pary (więc da się wyczyścić drzewo wtedy i tylko wtedy, gdy liczba liści jest parzysta) oraz każda krawędź drzewa ma należeć na co najmniej jednej najkrótszej ścieżce między jakimiś sparowanymi liśćmi.

Mając dane drzewo n-wierzchołkowe (3n105) oraz q operacji (1q105), należy po każdej operacji wypisać minimalny koszt wyczyszczenia drzewa. Każda operacja jest wykonywana niezależnie (czyli na niezmienionym drzewie) i polega na dodaniu dodatkowych synów do wybranych wierzchołków oryginalnego drzewa (suma ilości dodanych synów po wszystkich operacjach nie przekracza 105).

Podzadanie 2

Ograniczenia: zachodzi q=1, istnieje krawędź między wierzchołkiem 1 oraz i dla 2in oraz nie są dodawane wierzchołki do wierzchołka 1.

Po dodaniu nowych liści, jeżeli istnieje wierzchołek posiadający co najmniej dwa liście, to można liście zachłannie między sobą parować (przy czym trzeba uważać na to, aby nie sparować ze sobą wszystkich liści, które są synami wierzchołka niebędącego korzeniem). Po tym można zauważyć, że nieważne jak sparujemy wierzchołki, to ścieżka między każdą parą wierzchołków przechodzi przez korzeń, więc wystarczy tylko rozpatrywać sumę odległości liści do korzenia.

Parzyste i nieparzyste wierzchołki

Można udowodnić, że w rozwiązaniu optymalnym, każda krawędź zostanie wyczyszczona co najwyżej dwukrotnie (szkic dowodu jest następujący -- jeżeli istnieje taka krawędź, która jest wyczyszczona co najmniej trzykrotnie, to zamiast łączyć ze sobą pewną ilość par wierzchołków po różnych stronach krawędzi, lepiej jest złączyć takie, co są po tej samej stronie).

Należy więc zminimalizować liczbę krawędzi drzewa, które zostaną wyczyszczone dwukrotnie.

Dla wygody ukorzeńmy sobie drzewo w wierzchołku niebędącym liściem. Niech parent(v) będzie ojcem wierzchołka v. Niech v będzie nazwany parzystym, jeżeli w jego poddrzewie jest parzyście wiele liści (analogicznie nieparzysty).

Dana krawędź od v do parent(v) na pewno będzie musiała być dwukrotnie czyszczona, gdy v jest parzystym wierzchołkiem. Można też wykazać, że jeżeli v jest nieparzysty, to zawsze można ją jednokrotnie czyścić.

Z tego wynika, że odpowiedzią dla dowolnego drzewa jest n+|P|2, gdzie P to zbiór parzystych wierzchołków i można to obliczyć w O(n) dla n-wierzchołkowego drzewa poprzez pojedynczego DFS-a.

Jeżeli taki algorytm zostanie użyty dla każdego zapytania, to otrzyma się rozwiązanie w złożoności O(nq+Di), gdzie Di to liczba dodanych liści w i-tym zapytaniu.

Podzadanie 4

Dla n20000,q300 można użyć powyższego algorytmu.

Podzadanie 5 oraz 6

Gdy jest dodawany liść do wierzchołka v, parzystość wierzchołków v,parent(v),parent(parent(v)), się zmienia. Podejściem używanym w obu podzadaniach jest utrzymywanie parzystości wierzchołków oraz sumaryczną liczbę parzystych wierzchołków.

Zależnie od podzadania:

Podzadanie 7 -- rozwiązanie z drzewem wirtualnym

Zauważmy, że gdy dodamy liść do wierzchołka v oraz do wierzchołka u, to wierzchołek LCA(v,u) nie zmieni parzystości (ani wyższe wierzchołki na ścieżce do korzenia).

Niech zbiór Li to zbiór wierzchołków, które w danej operacji mają dodanego co najmniej jednego nowego syna. Niech W(Li) będzie zbiorem wierzchołków drzewa wirtualnego zdefiniowanego przez zbiór Li, czyli W(Li) składa się ze zbioru Li oraz LCA każdej pary wierzchołków Li. Można udowodnić, że |W(Li)|=min(n,2Di1) i można go skonstruować po prostu biorąc wszystkie wierzchołki Li i biorąc LCA kolejnych dwóch wierzchołków ciągu Li posortowanego według numerów preorder całego drzewa. Mając zbiór W(Li), można teraz skonstruować drzewo wirtualne Wi, czyli takie drzewo o zbiorze wierzchołków W(Li), gdzie v jest przodkiem u w tym drzewie, jeżeli v jest przodkiem u w oryginalnym drzewie.

W drzewie Wi dla każdego wierzchołka policzmy liczbę nowo dodanych liści w jego poddrzewie. Jeżeli dla wierzchołka vW(Li) ta liczba jest nieparzysta, to wszystkie wierzchołki w oryginalnym drzewie na ścieżce od v do parent(v,Wi) (ale nie wliczając parent(v,Wi)) zmienią swoją parzystość. Jeżeli ta liczba jest parzysta, nic się nie zmienia.

Zadanie więc zostało sprowadzone do obliczenia wyniku po zmienieniu parzystości O(Di) rozłącznych ścieżek w oryginalnym drzewie. Korzystając z podejścia z podzadania 6, w O(1) można policzyć zmianę w liczbie parzystych wierzchołków po zmienieniu parzystości wierzchołków na wybranej ścieżce (korzystając z podejścia, że ścieżka od v do jego przodka u to jest ścieżka od v do korzenia, „odjąć” ścieżka od ojca u do korzenia).

Podzadanie 7 -- rozwiązanie z HLD

Operacje z podzadania 6 można rozwiązać w O(Dilog2n) za pomocą heavy-light decomposition z operacjami zmienienia stanu wierzchołków (parzysty lub nieparzysty) na wybranej ścieżce oraz policzenia liczby wierzchołków z danym stanem.

Podzadanie 7 -- rozwiązanie z mniejszym do większego

Dla każdego wierzchołka spreprocessujmy indeksy operacji, które sprawią, że w tym wierzchołku zostanie doczepiony nowy syn. Wtedy, DFS-em od liści do korzenia można sparować niesparowane liście. Takie niesparowane liście (identyfikowane poprzez numer oryginalnego liścia lub numer operacji dodającej tego liścia) można trzymać w secie, a w każdym wierzchołku w tym DFS-ie należy w pewien sposób złączyć takie dwa zbiory.

Jeżeli spotkamy dwóch synów mających niesparowany wierzchołek dodany przez taką samą operację, to aktualny wierzchołek jest LCA tych dwóch liści, więc można odpowiednio policzyć zmianę w liczbie parzystych wierzchołków.

Taki algorytm daje tylko zmianę wyniku w porównaniu do oryginalnego drzewa. Należy więc jeszcze policzyć wynik oryginalnego drzewa, bez żadnych operacji.

Żeby zachować złożoność mniejszą niż kwadratowa, można zawsze łączyć mniejszy zbiór do większego (co jest potocznie nazywane „metodą mniejszy do większego”), otrzymując złożoność O((n+Di)log(n+Di)+q).