Submission #1040864

#TimeUsernameProblemLanguageResultExecution timeMemory
1040864crimson231Demarcation (BOI14_demarcation)C++17
100 / 100
77 ms23736 KiB
//Not my code /* Rozwiazanie wzorcowe do zadania Demarkacja * Podaje w pierwszj kolejnosci odcinki pionowe * Autor: Marek Sommer */ #include <cstdio> #include <algorithm> typedef long long int ll; // wartosci bezwzgledne inline int bez(int x) { return x<0?-x:x; } inline ll bez(ll x) { return x<0?-x:x; } // minimum/maksimum inline int min(int a,int b) { return a<b?a:b; } inline int max(int a,int b) { return a<b?b:a; } // czy punkt nalezy do przedzialu domknietego [min(p,k),max(p,k)] inline bool w_przedziale(int p,int k,int x) { if(p>k) return w_przedziale(k,p,x); return p <= x && x <= k; } // iloczyn_wektorowy inline ll ilwek(int ax,int ay,int bx,int by) { return static_cast<ll>(ax)*by-static_cast<ll>(ay)*bx; } // element listy wierzcholkow wielokata struct wielokat { wielokat *nas; // wskaznik na nastepny wierzcholek wielokata wielokat *pop; // wskaznik na poprzedni wierzcholek wielokata int x,y; // wspolrzdne wierzcholka // dodaje nowy wierzcholek, za aktualnym wielokat *dodaj_za(int _x,int _y) { wielokat *wie=new wielokat; wie->x=_x; wie->y=_y; wie->pop=this; wie->nas=this->nas; this->nas->pop=wie; this->nas=wie; return wie; } // usuwa dany wierzcholek // !!! nie wywolue delete !!! void usun() { this->nas->pop = this->pop; this->pop->nas = this->nas; } // dodaje nowy wierzcholek przed aktualnym wielokat *dodaj_przed(int _x,int _y) { return this->pop->dodaj_za(_x,_y); } // cztery ponizsze funkcje stwierdzaja, czy krawedz za/przed tym wierzcholkiem jest pionowa/pozioma bool nas_poz() { return (this->y == this->nas->y); } bool nas_pio() { return (this->x == this->nas->x); } bool pop_poz() { return this->pop->nas_poz(); } bool pop_pio() { return this->pop->nas_pio(); } // funkcje, ktore stwierdzaja, czy nastepny/poprzedni wierzcholek ma wporzedna wieksza (1), czy mniejsza (-1) int nas_znak() { if(nas_poz()) return ((this->x)<(this->nas->x))?1:-1; else return ((this->y)<(this->nas->y))?1:-1; } int pop_znak() { return -(this->pop->nas_znak()); } // dlugosc krawedzi za/przed aktualnym wierzcholkiem int nas_odl() { return bez((this->x)-(this->nas->x))+bez((this->y)-(this->nas->y)); } int pop_odl() { return this->pop->nas_odl(); } // pole prostokata miedzy nastepna/poprzednia krawedzia, a osia x // to pole ma byc skierowane! ll nas_pol() { return static_cast<ll>((this->nas->x)-(this->x))*(this->y); } ll pop_pol() { return this->pop->nas_pol(); } }; int n; // liczba wierzcholkow wielokata ll obwod; // obwod wielokata ll obw; // polowa obowdu wielokata ll pole; // pole wielokata !!! pole jest skierowane !!! ll pol; // polowa pola wielokata !!! pole jest skierowane !!! wielokat *poc; // wskaznik na pierwszy wierzcholek wielokata // Funkcja do przesuwania wskaznika do odleglosci rownej polowie obwodu // k=wskaznik, ktory nalezy przesunac // odl=suma dlugosci odcinkow miedzy wskaznikami void przesun(wielokat * & k,ll &odl,ll &po) { while(odl+(k->nas_odl())<=obw) { odl+=k->nas_odl(); po+=k->nas_pol(); k=k->nas; } } // Chodzenie dwoma wskaznikami po obwodzie i tworzenie wierzcholkow na krawedziach // Tworzone sa takie wierzcholki, ktore sa w odleglosci polowy obwodu od jakiegos innego wierzcholka void dodaj_wierzcholki() { wielokat *prz=poc; ll odl=0LL; ll po; // zmienna nieuzywana wielokat *wsk=poc; do { przesun(prz,odl,po); if(odl!=obw) { if(prz->nas_poz()) prz=prz->dodaj_za((prz->x)+(obw-odl)*(prz->nas_znak()),prz->y); else prz=prz->dodaj_za(prz->x,(prz->y)+(obw-odl)*(prz->nas_znak())); odl=obw; } odl-=wsk->nas_odl(); wsk=wsk->nas; } while(wsk!=poc); } // drzewo przedzialowe z operacjami: // - dodaj wartosc w punkcie // - odczytaj sume wartosci z przedzialu int drzewo[2100005]; int n2; // rozmiar drzewa (liczba lisci, indeksowanych od 0 do (n2-1)) int drz_skal[1000005]; // mozliwe pozycje w drzewie - do skalowania ukladu wspolrzednych int drz_skal_n; // liczba wartosci w tablicy drz_skal // funkcja, ktora zwraca indeks wartosci w tablicy drz_skal: int drz_skal_pozycja(int w) { return static_cast<int>(std::lower_bound(drz_skal,drz_skal+drz_skal_n,w)-drz_skal); } // funkcja, ktora dodaje wartosc w punkcie void dodaj(int x,int w) { x=n2+drz_skal_pozycja(x); while(x) { drzewo[x]+=w; x/=2; } } // funkcja, ktora odczytuje sume wartosci z przedzialu (a,b) - !!! bez punktow a i b !!! int suma(int a,int b) { a=n2+drz_skal_pozycja(a); b=n2+drz_skal_pozycja(b); if(a+1>=b) return 0; // przedzial nie zawiera punktow calkowitych a++; b--; // teraz szukam na przedziale [a,b] - wlacznie int wynik=drzewo[a]; if(a!=b) wynik+=drzewo[b]; while((a/2)!=(b/2)) { if(a%2==0) wynik+=drzewo[a+1]; if(b%2==1) wynik+=drzewo[b-1]; a/=2; b/=2; } return wynik; } // struktura opisujaca zdarzenie, podczas zamiatania krawedzi wielokota, // w poszukiwaniu przeciec potencjalnych odcinkow z bokami figury struct zdarzenie { int x; // wspolrzedna x zdarzenia int a,b; // oba te parametry przechowuja inne informacje w zaleznosci // od tego, co to jest za typ zdarzenia // jesli zdarzeniem jest poczatek poziomego odcinka (krawedzi wielokata), // to a jest wspolrzedna y tego odcinka, natomiast b= -1 // jesli zdarzeniem jest koniec poziomego odcinka (krawedzi wielokata), // to a jest wspolrzedna y tego odcinka, natomiast b= -2 // jesli zdarzeniem jest pionowy odcinek do sprawdzenia, // to a jest mniejsza wsporzedna y, natomiast b jest wieksza wspolrzedna y tego odcinka }; zdarzenie make_zda(int x,int a,int b) { zdarzenie z; z.x=x; z.a=a; z.b=b; return z; } bool porownanie_zdarzen(zdarzenie a,zdarzenie b) { // zdarzenia sa sortowane przede wszystkim po wspolrzednej x // jesli jest rowna, to najpierw poczatki odcinkow, potem pionowe odcinki, a na koncu konce odcinkow poziomych if(a.x==b.x) { if(b.b== -1) return false; if(a.b== -1) return true; if(a.b== -2) return false; if(b.b== -2) return true; return false; } return a.x<b.x; } // tablica ze zdarzeniami zdarzenie zda[1000005]; // potrzebny jest az milion zdarzen int z; // liczba zdarzen w tablicy zda // funkcja probuje wybrac poziomy odcinek miedzy wierzcholkami p i k, // przy zalozeniu, ze sa w dobrej odleglosci od siebie (polowa obowdu) // stara sie tez zachowac poprawne pole // jesli p i k maja rozne wspolrzedne x, to wybiera jakis odcinek pomiedzy nimi tak, // aby obwod, pole i przynaleznosc koncow odcinka do wielokata sie zgadzaly void sprobuj_odcinek_miedzy(wielokat *p,wielokat *k,ll po) { int d=bez((p->x)-(k->x)); // d = odleglosc (na osi x) miedzy wierzcholkami p i k if(d==0 && po==pol) { zda[z++]=make_zda(p->x,min(p->y,k->y),max(p->y,k->y)); return; } if(d%2==1) return; if(!(p->nas_poz()) || !(k->nas_poz())) return; // oba nastepne odcinki musza byc poziome d/=2; int px,kx; // wspolrzedne przesunietych wierzcholkow p i k o odleglosc d w strone zgodna z lista wierzcholkow px = (p->x) + (p->nas_znak())*d; kx = (k->x) + (k->nas_znak())*d; if(px!=kx) return; // czy ten punkt da sie w ogole uzyskac if(!w_przedziale(p->x,p->nas->x,px) || !w_przedziale(k->x,k->nas->x,kx)) return; // punkty leza poza odcinkami if((po-static_cast<ll>(px-(p->x))*(p->y)+static_cast<ll>(kx-(k->x))*(k->y))!=pol) return; // pola musza sie zgadzac zda[z++]=make_zda(px,min(p->y,k->y),max(p->y,k->y)); } // szukaj_pio() szuka pionowego odcinka podzialu wielokata na dwie czesci o rownym obwodzie i rownym polu // jesli taki istnieje, to jego wspolrzedne zapisuje w ponizszych zmiennych // Jesli pionowy odcinek podzialu istnieje, to funkcja zwraca tez true, // w przeciwnym wypadku zwraca false int wyn_x1,wyn_x2,wyn_y1,wyn_y2; bool szukaj_pio() { z=0; // czyszczenie tablicy zdarzen wielokat *p = poc; // ustalony wskaznik wielokat *k = poc; // wskaznik, ktory sie porusza ll odl=0LL; // obwod fragmentu wielokata od p do k ll po=0LL; // pole fragmentu wielokata od p do k while(true) // petla jest przerywana, kiedy drugi wskaznik (k) przejdzie na poczatek wielokata { przesun(k,odl,po); if(k==poc) break; sprobuj_odcinek_miedzy(p,k,po); p=p->nas; odl-=p->pop_odl(); po-=p->pop_pol(); } // dodawanie poziomych krawedzi wielokata do kolejki zdarzen // oraz poszukiwanie mozliwych wartosci y do drzewa przedzialowego drz_skal_n=0; p=poc; do { if(p->nas_poz()) zda[z++]=make_zda(p->x,p->y,(p->nas_znak()==1)?(-1):(-2)); if(p->pop_poz()) zda[z++]=make_zda(p->x,p->y,(p->pop_znak()==1)?(-1):(-2)); drz_skal[drz_skal_n++]=(p->y); p=p->nas; } while(p!=poc); // sortowanie zdarzen std::sort(zda,zda+z,porownanie_zdarzen); // inicjalizacja drzewa przedzialowego std::sort(drz_skal,drz_skal+drz_skal_n); drz_skal_n=static_cast<int>(std::unique(drz_skal,drz_skal+drz_skal_n)-drz_skal); n2=1; while(n2<drz_skal_n) n2*=2; for(int i=1;i<(n2*2);i++) drzewo[i]=0; // przechodzenie kolejnych zdarzen for(int i=0;i<z;i++) { if(zda[i].b== -1) // poczatek odcinka { dodaj(zda[i].a,1); } else if(zda[i].b== -2) // koniec odcinka { dodaj(zda[i].a,-1); } else // pionowy odcinek { if(suma(zda[i].a,zda[i].b)==0) // odcinek pionowy nie przecina zadnego odcinka poziomego { wyn_x1=wyn_x2=zda[i].x; wyn_y1=zda[i].a; wyn_y2=zda[i].b; return true; } } } return false; } // funkcja, ktora znajduje wierzcholek wielokata, o wspolrzednych (x,y) // jesli taki nie istnieje, to znajduje wierzcholek, po ktorym nastepuje krawedz zawierajaca ten punkt wielokat *wierzcholek_ze_wspolrzednych(int x,int y) { wielokat *p=poc; while(true) { if((p->x)==x && (p->y)==y) break; if(p->nas_poz() && (p->y)==y && bez(x-(p->x))<(p->nas_odl()) && (x-(p->x))*(p->nas_znak())>0) break; if(p->nas_pio() && (p->x)==x && bez(y-(p->y))<(p->nas_odl()) && (y-(p->y))*(p->nas_znak())>0) break; p=p->nas; } return p; } // zamien_wielokat_na_slowo zamienia wielokat w postaci listy wierzcholkow // na ciag liczb, oznaczajacych: // -1 -- kat 90 stopni // -2 -- kat -90 stopni // dodatnia liczba -- dlugosc boku // przy czym w tym ciagu znajduja sie na przemian liczby dodatnie i ujemne // ciag zaczyna sie liczba ujemna i konczy dodatnia // wartoscia zwracana jest dlugosc ciagu int zamien_wielokat_na_slowo(wielokat *w,int *tab) { int dlugosc=0; while((w->nas_poz()) == (w->pop_poz())) w=w->nas; wielokat *wsk=w; do { if((wsk->nas_poz()) == (wsk->pop_poz())) tab[dlugosc]+=wsk->nas_odl(); else { ll iloczyn_wektorowy=ilwek((wsk->x)-(wsk->pop->x),(wsk->y)-(wsk->pop->y),(wsk->nas->x)-(wsk->x),(wsk->nas->y)-(wsk->y)); if(iloczyn_wektorowy<0) tab[++dlugosc]= -1; else tab[++dlugosc]= -2; tab[++dlugosc]=wsk->nas_odl(); } wsk=wsk->nas; } while(wsk!=w); return dlugosc; } // znajdz_wzorzec szuka wzorca wzo (o dlugosci dw) w tekscie tek (o dlugosci dt) // jesli znajdzie, to zwraca true, jesli nie znajdzie to zwraca false int pref[1000005]; // tablica prefiksowa, uzywana przez znajdz_wzorzec bool znajdz_wzorzec(int dw,int *wzo,int dt,int *tek) { pref[0]= -1; for(int i=1;i<=dw;i++) { pref[i]=pref[i-1]; while(pref[i]!= -1 && wzo[pref[i]+1]!=wzo[i]) pref[i]=pref[pref[i]]; pref[i]++; } int d=0; for(int i=1;i<=dt;i++) { while(d!= -1 && wzo[d+1]!=tek[i]) d=pref[d]; d++; if(d==dw) return true; } return false; } // czy_przystajace stwierdza, czy wielokaty opisane slowami s1 i s2 sa przystajace bool czy_przystajace(int dlugosc,int *s1,int *s2) { int d2=dlugosc*2; for(int i=1;i<=dlugosc;i++) s2[dlugosc+i]=s2[i]; if(znajdz_wzorzec(dlugosc,s1,d2,s2)) return true; for(int i=1;i<=dlugosc/2;i++) std::swap(s1[i],s1[dlugosc-i+1]); if(znajdz_wzorzec(dlugosc,s1,d2,s2)) return true; return false; } // funkcja dzieli stwierdza, czy odcinek (x1,y1)--(x2,y2) dzieli wielokat // na dwa wielokaty przystajace // zaklada jednak, ze jest to odcinek pionowy i poza koncami nie ma czesci wspolnej z wielokatem // !!! ta funkcja jest napisana tak, aby pozostawila wszystkie zmienne globalne tak, jak je zastala !!! // !!! jest tylko jeden wyjatek -- kiedy odpowiedzia jest true, to moze sie dziac co chce !!! int wiel1[1000005]; // pomocnicza tablica na jeden wielokat int wiel2[1000005]; // pomocnicza tablica na drugi wielokat bool dzieli(int x1,int y1,int x2,int y2) { wielokat *p=wierzcholek_ze_wspolrzednych(x1,y1); wielokat *k=wierzcholek_ze_wspolrzednych(x2,y2); bool dodane_p=false; if((p->x)!=x1 || (p->y)!=y1) { dodane_p=true; p=p->dodaj_za(x1,y1); } bool dodane_k=false; if((k->x)!=x2 || (k->y)!=y2) { dodane_k=true; k=k->dodaj_za(x2,y2); } // wierzcholi przed/po p/k wielokat *p_nas,*p_pop,*k_nas,*k_pop; p_nas=p->nas; p_pop=p->pop; k_nas=k->nas; k_pop=k->pop; p->nas=k; k->pop=p; int wiel1_roz=zamien_wielokat_na_slowo(p,wiel1); p->nas=p_nas; k->pop=k_pop; p->pop=k; k->nas=p; int wiel2_roz=zamien_wielokat_na_slowo(p,wiel2); p->pop=p_pop; k->nas=k_nas; if(wiel1_roz==wiel2_roz) if(czy_przystajace(wiel1_roz,wiel1,wiel2)) return true; // usuwanie, jesli potrzeba if(dodane_p) { p->usun(); delete p; } if(dodane_k) { k->usun(); delete k; } return false; } int main() { scanf("%d",&n); poc=new wielokat; scanf("%d%d",&(poc->x),&(poc->y)); poc->nas=poc; poc->pop=poc; for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); poc->dodaj_przed(x,y); } // Liczenie obwodu wielokata obwod=poc->nas_odl(); for(wielokat *i=poc->nas;i!=poc;i=i->nas) obwod+=i->nas_odl(); obw=obwod/2; // Liczenie pola wielokata pole=poc->nas_pol(); for(wielokat *i=poc->nas;i!=poc;i=i->nas) pole+=i->nas_pol(); if(pole%2==1) { printf("NO\n"); return 0; } pol=pole/2; // Tworzenie brakujacych wierzcholkow na krawedziach dodaj_wierzcholki(); if(szukaj_pio()) { if(dzieli(wyn_x1,wyn_y1,wyn_x2,wyn_y2)) { printf("%d %d %d %d\n",wyn_x1,wyn_y1,wyn_x2,wyn_y2); return 0; } } wielokat *tmp=poc; do { std::swap(tmp->x,tmp->y); tmp=tmp->nas; } while(tmp!=poc); pole*= -1; pol*= -1; if(szukaj_pio()) { if(dzieli(wyn_x1,wyn_y1,wyn_x2,wyn_y2)) { printf("%d %d %d %d\n",wyn_y1,wyn_x1,wyn_y2,wyn_x2); return 0; } } printf("NO\n"); return 0; }

Compilation message (stderr)

demarcation.cpp: In function 'int main()':
demarcation.cpp:420:7: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
  420 |  scanf("%d",&n);
      |  ~~~~~^~~~~~~~~
demarcation.cpp:422:7: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
  422 |  scanf("%d%d",&(poc->x),&(poc->y));
      |  ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
demarcation.cpp:427:8: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
  427 |   scanf("%d%d",&x,&y);
      |   ~~~~~^~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...