Brylanty z kosmosu – omówienie zadania

Szczegółowe omówienie zadania Brylanty z kosmosu:

Link do powyższego omówienia zadania Brylanty z kosmosu:
https://youtu.be/0ri7j0X_Oqo?t=1649

Link do treści zadania Brylanty z kosmosu oraz możliwości umieszczania rozwiązań:
https://szkopul.edu.pl/problemset/problem/bzk/site/


Zadanie Brylanty z kosmosu jest szkoleniowym zadaniem pokazującym drzewa przedział-przedział:
https://youtu.be/hHNjFBxNO54?t=2197
Drzewa przedziałowe to sumy prefiksowe z mała obserwacją:
https://youtu.be/hHNjFBxNO54?t=2159
Wszystko jesteśmy w stanie udoskonalić:
https://youtu.be/hHNjFBxNO54?t=29


Jak się uczyć na podstawie tego zadania?
https://youtu.be/QgLyXYmFQeU?t=2019
Pamiętaj by zajrzeć max 1 raz – wtedy się rozwijasz:
https://youtu.be/pkLXuuOe_qA?t=3625


Kod C++ programu Brylanty z kosmosu, który jest omówiony w powyższym filmie i który otrzymuje 100%


#include <iostream>
#include <vector>
std::vector<int> suma_na_przedziale;
std::vector<int> nie_zaktualizowane_wartosci_synow;
int ZnajdzNajblizszaWiekszaPotegeDwojki (int liczba) {
int najblizsza_potega_dwojki;
najblizsza_potega_dwojki = 1;
while (najblizsza_potega_dwojki < liczba)
najblizsza_potega_dwojki <<= 1;
return najblizsza_potega_dwojki;
}
void PrzekazNiezaktualizowaneWartosciSynom (int wierzcholek) {
int syn_lewy, syn_prawy;
syn_lewy  = 2*wierzcholek;
syn_prawy = 2*wierzcholek + 1;
suma_na_przedziale[syn_lewy]  += nie_zaktualizowane_wartosci_synow[wierzcholek];
suma_na_przedziale[syn_prawy] += nie_zaktualizowane_wartosci_synow[wierzcholek];
nie_zaktualizowane_wartosci_synow[syn_lewy]  += nie_zaktualizowane_wartosci_synow[wierzcholek]/2;
nie_zaktualizowane_wartosci_synow[syn_prawy] += nie_zaktualizowane_wartosci_synow[wierzcholek]/2;
nie_zaktualizowane_wartosci_synow[wierzcholek]  = 0;
}
void DodajWartoscNaPrzedzialeWDrzewie (int wartosc, int poczatek_podanego_przedzialu, int koniec_podanego_przedzialu,
int wierzcholek, int poczatek_zakresu_wierzcholka, int koniec_zakresu_wierzcholka) {
int srodek, suma;
//jesli mamy doda cos na przedziale za ktry nasz wierzchoek NIE odpowiada - chocby czciowo - wychodzimy
if ( koniec_podanego_przedzialu < poczatek_zakresu_wierzcholka)
return;
if ( poczatek_podanego_przedzialu > koniec_zakresu_wierzcholka)
return;
//jesli mamy doda cos na takim przedziale, w ktrym zakres naszego wierzchoka mieci si w caoci
//to aktulizujemy sum za ktra odpowiada nasz wierzchoek
//nie aktulizujemy naszych dzieci - zrobimy to w przyzoci gdy bdzie trzeba na podstawie
//tablicy nie_zaktualizowane_wartosci_synow
if ( (poczatek_zakresu_wierzcholka >= poczatek_podanego_przedzialu) && 
(koniec_zakresu_wierzcholka <= koniec_podanego_przedzialu) ) {
suma = wartosc * (koniec_zakresu_wierzcholka - poczatek_zakresu_wierzcholka + 1);
suma_na_przedziale[wierzcholek] += suma;
nie_zaktualizowane_wartosci_synow[wierzcholek] += suma/2;
return;
}
//jesli nasz przedzia zawiera fagment czsciowo zakres na ktrym dodajemy
//ale te przedzia spoza aktulizowanego zakresu 
//to aktualizujemy synw z wczeniejszych pytan (nie_zaktualizowane_wartosci_synow)
//oraz przekazujemy im aktualny rozkaz
//nastepnie aktulizujemy nasz sum
PrzekazNiezaktualizowaneWartosciSynom (wierzcholek);
srodek = (poczatek_zakresu_wierzcholka + koniec_zakresu_wierzcholka) / 2;
DodajWartoscNaPrzedzialeWDrzewie (wartosc, poczatek_podanego_przedzialu, koniec_podanego_przedzialu,
2*wierzcholek, poczatek_zakresu_wierzcholka, srodek);
DodajWartoscNaPrzedzialeWDrzewie (wartosc, poczatek_podanego_przedzialu, koniec_podanego_przedzialu,
2*wierzcholek+1, srodek+1, koniec_zakresu_wierzcholka);
suma_na_przedziale[wierzcholek] = suma_na_przedziale[2*wierzcholek] + suma_na_przedziale[2*wierzcholek+1]; 
}
int ObliczSumePrzedzialuWDrzewie (int poczatek_podanego_przedzialu, int koniec_podanego_przedzialu,
int wierzcholek, int poczatek_zakresu_wierzcholka, int koniec_zakresu_wierzcholka) {
int suma_przedzialu_syna_lewego, suma_przedzialu_syna_prawego;
int srodek;
//jeli pytanie spoza zakresu wierzchoka to zwracamy 0 - suma ktr dokada ten wierzchoek do wyniku jest 0
if ( koniec_podanego_przedzialu < poczatek_zakresu_wierzcholka )
return 0;
if ( poczatek_podanego_przedzialu > koniec_zakresu_wierzcholka )
return 0;
//jeli nasz wierzchoek w caoci zawiera si w pytanym zakresie to nasz wierzchoek dokada si do sumy w caoci
//zwracamy sum ktr przechowuje nasz wierzchoek
if ( (poczatek_zakresu_wierzcholka >= poczatek_podanego_przedzialu) && 
(koniec_zakresu_wierzcholka <= koniec_podanego_przedzialu) ) {
return suma_na_przedziale[wierzcholek];
}
//jeli nasz wierzchoek zawiera co z pytanego zakresu ale te co spoza pytanego zakresu to nie moemy od razu odpowiedzie
//pytamy synw i zwracamy sum ich odpowiedzi
//ale najpierw aktualizujemy ich wartoci wczeniejszymi zapytaniami na ktre nie musieli odpowiada
PrzekazNiezaktualizowaneWartosciSynom (wierzcholek);
srodek = (poczatek_zakresu_wierzcholka + koniec_zakresu_wierzcholka) / 2;
suma_przedzialu_syna_lewego = ObliczSumePrzedzialuWDrzewie (poczatek_podanego_przedzialu, koniec_podanego_przedzialu,
2*wierzcholek, poczatek_zakresu_wierzcholka, srodek);
suma_przedzialu_syna_prawego = ObliczSumePrzedzialuWDrzewie (poczatek_podanego_przedzialu, koniec_podanego_przedzialu,
2*wierzcholek+1, srodek+1, koniec_zakresu_wierzcholka);
return suma_przedzialu_syna_lewego + suma_przedzialu_syna_prawego;
}  
int main (){
std::ios_base::sync_with_stdio(0);
std::cin.tie(0);
std::cout.tie(0);
int ile_pracownikow, ile_operacji;
char operacja;
int liczba_przechowywanych_elementow, rozmiar_drzewa;
int poczatek, koniec, wartosc;
int i;
std::cin >> ile_pracownikow >> ile_operacji;
//drzewo musi przechowywa elementy bdce potg dwjki
//rozmiar drzewa jest dwa razy wikszy od iloci przechowywanych elementw    
liczba_przechowywanych_elementow = ZnajdzNajblizszaWiekszaPotegeDwojki (ile_pracownikow);
rozmiar_drzewa = 2 * liczba_przechowywanych_elementow;
suma_na_przedziale.resize(rozmiar_drzewa, 0);
nie_zaktualizowane_wartosci_synow.resize(rozmiar_drzewa, 0);
for (i=1; i<=ile_operacji; ++i) {
std::cin >> operacja >> poczatek >> koniec;
if ( operacja == 'P') {
std::cout << ObliczSumePrzedzialuWDrzewie (poczatek-1, koniec-1, 1, 0, liczba_przechowywanych_elementow-1) << "\n";
continue;
}
std::cin >> wartosc;
DodajWartoscNaPrzedzialeWDrzewie (wartosc, poczatek-1, koniec-1, 1, 0, liczba_przechowywanych_elementow-1);
}
return 0;
}
Kod C++ programu Brylanty z kosmosu, który jest omówiony w powyższym filmie i który otrzymuje 100%

 

Nie dodano jeszcze komentarza, rozpocznij dyskusję pierwszy.

Dodaj komentarz