Informatyczny kącik olimpijski
Słownik przekątnych
W tym odcinku zajmiemy się zadaniem, które zamiast na zawodach, pojawiło się na... kolokwium (z Algorytmów i Struktur Danych). Stanowiłoby ono bardzo ładne zadanie na zawodach.
Od czego zacząć? Na początek może ułatwimy sobie zadanie — zauważmy, że wielokąt z zadania można „wygiąć” na płaszczyźnie, aż wierzchołki utworzą ciąg punktów na prostej, ponumerowanych od do , a przekątne zamienią się na łuki (jak na rysunku 1). Resztę zadania łatwo przetłumaczyć do tej nowej wersji. W tym momencie już pojawia się pomysł — może uda się użyć drzewa przedziałowego? Ale zanim napiszemy jak, wyjaśnijmy sobie, co będziemy rozumieć przez drzewo przedziałowe.
Drzewo przedziałowe (rys. 2) służy do przechowywania informacji związanych z podprzedziałami zadanego przedziału . W korzeniu drzewa jest zapisana informacja związana z całym przedziałem, w jego dwóch synach informacje związane z lewą i prawą połową tego przedziału i tak dalej, aż wreszcie w liściach zapamiętywane są wartości odpowiadające pojedynczym punktom. Wartość przechowywaną w wierzchołku będziemy oznaczać
Jako ćwiczenie Czytelnik może w oparciu o drzewo przedziałowe skonstruować strukturę danych do obsługi dynamicznie zmieniającego się ciągu , dopuszczającą operacje (1) inicjuj wszystkie wyrazy na , (2) ustaw oraz (3) podaj sumę podciągu . Operacje (2) i (3) powinny działać w czasie .
No dobrze, ale jak to zastosować do naszego problemu?
Zapytajmy, kiedy w nowym modelu (tym z prostą), można połączyć dwa punkty i przekątną? Spójrzmy na rysunek 1. Dla danego niech oznacza najniższy łuk, który przecina pionowa półprosta wychodząca z punktu (dotknięcie nie liczy się jako przecięcie; wartością może być „pusty” łuk). Łuk od do można dodać dokładnie wtedy, gdy . Musimy więc szybko obliczać wartości funkcji . Do tego przyda się drzewo przedziałowe.
Przypuśćmy, że wiemy już, iż możemy dodać przekątną . Jak to zrobić? Otóż przekątna „pokryje” podciąg wierzchołków . Słowo pokryje oznacza, że półprosta wychodząca z każdego z wierzchołków z tego przedziału przetnie naszą przekątną, choć niekoniecznie jako pierwszą.
Funkcja dodająca przekątną będzie działać rekurencyjnie. Najpierw wywołujemy ją dla korzenia. Dodając przekątną w wierzchołku drzewa przedziałowego, wykonujemy operacje:
- •
- jeśli podprzedział z wierzchołka zawiera się w , to ustaw na niższy z łuków i (wysokość łuku można szybko obliczyć, jest to ),
- •
- jeśli podprzedział z wierzchołka jest rozłączny z , to nic nie rób,
- •
- w przeciwnym razie wywołaj funkcję dla dzieci wierzchołka
Łatwo zauważyć, że to najniższy spośród łuków zapamiętanych w wierzchołkach drzewa odpowiadających przedziałom pokrywającym punkt , czyli na ścieżce prowadzącej z korzenia do wierzchołka . Zatem można znaleźć w czasie .
Funkcja Sprawdź może działać na podobnej zasadzie, sprawdzając, czy w odwiedzanych po drodze wierzchołkach jest zapamiętana poszukiwana przekątna. (Każda wstawiona przekątna zostaje gdzieś zapamiętana, dlaczego?)
Aktualizację stanu struktury podczas usuwania przekątnej pozostawiamy Czytelnikowi.