Documente Academic
Documente Profesional
Documente Cultură
Abstract - Problema
AIB-urile sunt o structura de date care implementeaza eficient urmatoarea problema: avem un
vector de numere, si vrem sa raspundem la urmatoarele operatii asupra lui:
1. se incremeneaza/ decrementeaza un numar din vector
2. care este suma unei anumite subsecvente a vectorului?
Pentru un exemplu mai concret, vezi problema datorii.
Sa ne gandim la cateva posibile solutii: am putea sa implementam usor un algoritm naiv de
complexitate O(N), sau cu ceva efort sa folosim arborii de intervale pentru o complexitate
O(logN). In continuare va vom prezenta structura de date numita AIB, usor de implementat si de
aceeasi complexitate ca si arborii de intervale. Mai mult, deoarece acestia au constanta mult mai
mica decat arborii de intervale, in practica se vor dovedi mult mai rapizi si vor ocupa si mai
putina memorie.
Concret - Cum?
Fie V vectorul de numere care se modifica in timp real. Vom reprezenta AIB-ul folosind un alt
vector, pe care il vom denumi, sugestiv, AIB, cu urmatoarea semnificatie:
AIB[x] = suma subsecventei din V cu capetele: [x - 2k + 1; x], unde k = numarul de 0-uri
terminale din reprezentarea binara a lui x.
Indicele x 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Inceputul subsecventei asociata lui AIB[x] 1 1 3 1 5 5 7 1 9 9 11 9 13 13 15 1
Detalii implementare
Valoarea x - 2k + 1, unde k = numarul de 0-uri terminale se poate calcula foarte usor astfel:
#define zeros(x) ( (x ^ (x - 1)) & x )
Aceast define va calcula valoarea 2k pentru x, unde k = numarul de 0-uri terminale. Pentru a
intelege de ce, sa luam cateva exemple:
x 10011000 11001111
x-1 10010111 11001110
x ^ (x-1) 00001111 00000001
(x ^ (x-1)) & x 00001000 00000001
Folosind acest define, implementarea operatiilor devine foarte simpla.
neformatat
print?
01.void Add(int x, int quantity)
02.{
03. int i;
04.
05. for (i = x; i <= N; i += zeros(i))
06. AIB[i] += quantity;
07.}
08.
09.int Compute(int x)
10.{
11. int i, ret = 0;
12.
13. for (i = x; i > 0; i -= zeros(i))
14. ret += AIB[i];
15. return ret;
16.}
Functia Add(x, quantity) incrementeaza valoarea lui V[x] cu quantity, care poate fi si negativ
pentru a decrementa. Functia Compute(x) calculeaza suma V [1] + V [2] + ... + V [x]. Pentru a
calcula suma subsecventei V [L...U] folositi Compute(U) - Compute(L-1).
Complexitatea in timp a fiecarei operatii este O(logN), pentru ca, in cazul celei de-a doua
operatii, la fiecare pas ultimul bit nenul al lui i devine nul, si deci for-ul va itera de maxim log x
ori. Structura ocupa spatiu O(N), doar vectorul AIB.
Aplicatii
Sa presupunem ca problema initiala se restrange la a marca/ demarca o pozitie, si ne propunem
sa aflam care este cea de a K-a pozitie marcata.
O prima idee de rezolvare, de complexitate O(log2 N), este urmatoarea: cautam binar pozitia, si
la fiecare pas, pentru a compara pozitia curenta i cu solutia, calculam in O(logN) functia
cnt(i) := suma elementelor de pe pozitiile 1...i; cnt(i) reprezinta de fapt numarul de numere intre
1 si i, pe care il comparam cu K pentru a stii cum facem urmatorul pas.
A doua idee de rezolvare, de complexitate O(logN) se poate realiza optimizand prima idee.
Folosim cautarea binara a lui Patrascu si urmatoarea observatie: cnt(8+4) = cnt(8) + AIB[8+4],
cnt(16+4) = cnt(16) + AIB[16+4], etc. Daca ne uitam la cum functioneaza functia Compute(int
x), putem generaliza astfel: cnt(x) = cnt(x - zeros(x)) + AIB[x]. Implementarea propriu-zisa o
lasam ca tema pentru cititor, impreuna cu problema gasirii celui de-al K-lea numar dintr-un AIB
oarecare, pornind de la ideea de mai sus.
AIB-urile se pot extinde usor la cazul multidimensional, si lasam aceasta implementare ca tema
pentru cititor. De asemenea, incercati sa rezolvati urmatoarele probleme de pe infoarena:
1. Datorii
2. Ben
3. Evantai
4. Schi
Pentru o lectura mai profunda in acest domeniu, va recomand acest articol de pe TopCoder.
Arbori Indexati Binar.doc Arbori de intervale si aplicatii in geometria computationala
(Categoria Structuri de date, Autor Dana Lica)
Problema 1
Se considera N (N ≤ 50 000) segmente in plan, dispuse paralel cu axele OX si OY. Sa se
determine care este numarul total de intersectii dintre segmente.
In fisierul segment.in se gaseste pe prima linie numarul N de segmente, iar pe fiecare dintre
urmatoarele N linii cate patru numere naturale mai mici decat 50 000, reprezentand coordonatele
carteziene ale extremitatilor fiecarui segment. Rezultatul se va scrie in segment.out.
Timp de executie: 1 secunda/test.
segment.in segment.out Figura
5 4
2 9 13 9
4 6 12 6
1262
5058
7 5 7 11
Arbori de intervale
Un arbore de intervale este un arbore binar in care fiecare nod poate avea asociata o structura
auxiliara (anumite informatii). Dandu-se doua numere intregi st si dr, cu st < dr, atunci arborele
de intervale T(st, dr) se construieste recursiv astfel:
consideram radacina nod avand asociat intervalul [st, dr];
daca st < dr atunci vom avea asociat subarborele stang T(st, mij), respectiv subarborele
drept T(mij + 1, dr), unde mij este mijlocul intervalului [st, dr].
Intervalul [st, dr] asociat unui nod se numeste interval standard. Frunzele arborelui sunt
considerate intervale elementare, ele avand lungimea 1.
Proprietate:
Un arbore de intervale este un arbore binar echilibrat (diferenta absoluta intre adancimea
subarborelui stang si cea a subarborelui drept este cel mult 1). Astfel, adancimea unui arbore de
intervale care contine N intervale este [log2N] + 1.
Problema 3
Se dau N ≤ 100 000 puncte in plan de coordonate numere naturale mai mici ca 2 000 000 000. Sa
se raspunda la M ≤ 1 000 000 intrebari de forma "cate puncte din cele N exista in dreptunghiul cu
coltul stanga sus in (x1, y1) si coltul dreapta jos in (x2, y2)?".
In fisierul puncte.in se vor gasi pe prima linie numerele N si M. Pe urmatoarele N linii se vor gasi
coordonatele punctelor. Pe urmatoarele M linii se vor gasi cate patru numere naturale
reprezentand coordonatele colturilor dreptunghiurilor. In fisierul puncte.out se vor gasi M
numere naturale reprezentand raspunsurile la intrebari.
Timp maxim de executie: 1 secunda/test.
puncte.in puncte.out Figura
61 2
28
53
65
87
81
10 10
4894
Problema determinarii numarului de puncte din interiorul unui dreptunghi este o particularizare
bidimensionala pentru problema numita in literatura de specialitate Orthogonal Range Search.
Varianta aleasa pentru acest caz consta intr-un arbore de intervale, care permite determinarea
numarului de puncte din interiorul unui dreptunghi cu o complexitate O(log22 N).
Astfel, se sorteaza coordonatele x ale punctelor si se construieste un arbore de intervale. Primul
nivel al arborelui va contine toate coordonatele x. Cei doi fii ai lui vor contine prima jumatate,
respectiv a doua jumatate a punctelor (sortate dupa coordonata x) si asa mai departe. Pentru
fiecare interval de coordonate x, se mentin sortate coordonatele y corespunzatoare punctelor care
au coordonatele x in intervalul respectiv. Astfel, memoria folosita este O(N * log2N). Pentru a
construi efectiv se foloseste o abordare asemanatoare algoritmului de sortare prin interclasare: in
fiecare nod, pentru a obtine lista de coordonate y ordonate, se interclaseaza listelele celor doi fii
(deja ordonate). Cand se ajunge intr-o frunza, lista nodului este formata dintr-un singur punct.
Pentru fiecare dreptunghi, se executa cautarea in arborele de intervale pentru segmentul [x1, x2]
(deoarece se folosesc doar cele N coordonate x ale punctelor, se vor potrivi capetele acestui
interval folosind cautarea binara la cea mai apropiata coordonata x de fiecare capat). Pentru
fiecare interval din arbore atins, se executa doua cautari binare printre coordonatele y
corespunzatoare coordonatelor x din acel interval, pentru a determina cate puncte din intervalul
respectiv se afla in intervalul [y1, y2] (adica in interiorul dreptunghiului).
Complexitatea O(log22 N) poate fi redusa, folosind o metoda descoperita independent de Willard
si Lueker in anul 1978. Se observa ca pentru fiecare coordonata y dintr-un nod, daca presupunem
ca se efectueaza o cautare binara, atunci putem determina in timpul interclasarii pozitia din
fiecare fiu pe care o va returna cautarea binara pentru aceeasi valoare. Este evident ca pentru o
valoare y dintr-un nod care a provenit dintr-un fiu in timpul interclasarii, exista o unica valoare
maxima y' din celalalt fiu astfel incat y' ≤ y. Asadar, tinem pentru fiecare valoare y dintr-un nod
doi indici care identifica pozitiile corespunzatoare efectuarii unei cautari binare in fii pentru
valoarea y. Astfel, in timpul cautarii, in loc sa se efectueze cautari binare, se pot parcurge acesti
indici, care ofera in O(1) pozitia in lista cautata, reducand complexitatea totala la O(log2 N).
Probleme propuse
2001 1. Preluata de la Olimpiada Baltica de Informatica, Polonia
Se considera N ≤ 50 000 dreptunghiuri in plan, fiecare avand laturile paralele cu axele OX, OY.
Sa se calculeze aria ocupata de reuniunea celor N dreptunghiuri.
In fisierul drept2.in se gaseste pe prima linie numarul N de dreptunghiuri, iar pe fiecare din
urmatoarele N linii cate patru numere naturale mai mici ca 50 000, reprezentand coordonatele
carteziene ale coltului stanga sus, respectiv dreapta jos ale fiecarui dreptunghi. Rezultatul se va
scrie in fisierul drept2.out.
Timp maxim de executie: 1 secunda/test.
Nota
Au fost adaugate si implementarile in limbaj Pascal, C ale catorva dintre problemele explicate in
articol. Acestea pot fi accesate prin intermediul optiunii "Listeaza atasamente".
» 3 comentarii
Comenteaza si tu!
Evantai
Lui Algorel ii plac mult sirurile de numere naturale cu proprietati cat mai ciudate. Cautand astfel
de ciudatenii ale informaticii, a gasit printr-o carte prafuita de vreme un nou tip de sir denumit
evantai. Un evantai este un sir cu un numar par de termeni, E1 E2 ... E2K, cu urmatoarea
proprietate:
E1 + E2K > E2 + E2K-1 > ... > EK + EK+1
Cerinta
Fiind dat un sir de numere naturale distincte A1 A2 ... AN, Algorel vrea sa afle cate subsiruri ale
acestuia sunt evantaie.
Date de intrare
Prima linie a fisierului evantai.in contine numarul intreg N, reprezentand numarul de elemente
ale sirului. Urmatoarele N linii contin, in ordine, elementele sirului A.
Date de iesire
Pe prima linie a fisierului evantai.out se va afla un singur numar intreg C, reprezentand numarul
de subsiruri evantai. Rezultatul va fi afisat modulo 30103.
Restrictii si precizari
2 ≤ N ≤ 700
Prin subsir se intelege orice insiruire de termeni Ai1 Ai2 ... Aik astfel incat i1 < i2 < ... < ik
Exemplu
evantai.ou
evantai.in
t
4
1
2 7
3
6
Trebuie sa te autentifici pentru a trimite solutii. Click aici
Indicii de rezolvare
Arată 3 categorii
Cum se trimit solutii?
Datorii
Tatal si mama lui Gigel se ocupa cu vanzarea de sisteme de calcul. Afacerea s-a dovedit a fi
foarte profitabila datorita unui sistem incredibil de creditare a clientilor: un client care cumpara
un calculator in ziua X (in acest moment au trecut N zile de la infiintarea magazinului, zilele se
numeroteaza de la 1 la N, 0 < X ≤ N) poate returna banii oricand doreste acesta, neexistand o
limita de timp impusa. Astfel, aproape in fiecare zi, la magazinul familiei se prezinta diversi
clienti care achita integral sau partial un sistem de calcul cumparat in zilele anterioare. Deoarece
vor sa inceapa o noua afacere, Mama si Tata doresc sa il insarcineze pe Gigel cu administrarea
magazinului de calculatoare. Pentru aceasta Gigel trebuie sa indeplineasca o conditie esentiala:
in orice moment al sederii lui la magazin el poate fi solicitat prin telefon de catre tatal sa
raspunda cat mai repede la urmatoarea familie de intrebari: ce suma de bani a ramas inca
neachitata luand in considerare achizitiile facute de clienti in zilele P, P+1, P+2... Q-1, Q (0 < P
≤ Q ≤ N). Se stie ca niciodata nu s-au cumparat doua calculatoare in aceeasi zi. Ajuta-l pe Gigel
sa demonstreze parintilor ca poate administra magazinul.
Cerinta
Se dau: N, M, un sir de numere A1, A2... AN si M operatii. Ai (1 ≤ Ai ≤ 1000, 1 ≤ i ≤ N) reprezinta
suma de bani inca neachitata pentru o comanda efectuata in ziua i. O operatie poate fi de doua
feluri:
A (achitare - se scade o valoare din suma restanta a unei zile anume)
B (interogare - se cere suma tuturor sumelor restante ale unui interval de zile). Programul
trebuie sa scrie in fisierul de iesire suma ceruta de fiecare operatie de tip B in momentul
interogarii.
Date de intrare
Fisierul datorii.in va contine pe prima linie numerele N si M. Pe urmatoarea linie se afla valorile
sirului A1, A2... AN separate prin cate un spatiu. Urmatoarele M linii descriu operatiile (achitari
sau interogari) efectuate in ordinea data. Fiecare linie care descrie o operatie incepe cu un cod
binar (un numar intreg cu valoarea 0 sau 1) si continua cu 2 numere intregi.
Un cod 0 urmat de doua numere intregi T, V (1 ≤ T ≤ N, 1 ≤ V ≤ 1000) reprezinta o
operatie de tip A (in momentul respectiv s-a achitat o valoare V din suma restanta a zilei
T)
Un cod 1 urmat de doua numere intregi P, Q (1 ≤ P ≤ Q ≤ N) o operatie de tip B (se cere
suma tuturor sumelor restante din zilele P, P+1, P+2... Q in momentul respectiv).
Date de iesire
In fisierul datorii.out se vor scrie pe cate o linie sumele cerute de fiecare operatie de tip B
(sumele se cer in ordinea aparitiei operatiilor in fisierul de intrare).
Restrictii si precizari
1 ≤ N ≤ 15 000
0 < M ≤ 100 000
In orice moment, Ai (1 ≤ i ≤ N) este nenegativ.
Exemplu
datorii.in datorii.out
66
1 3 2 0 0 10
136 12
114 6
031 15
116 13
062
116
Trebuie sa te autentifici pentru a trimite solutii. Click aici
Indicii de rezolvare
Arată 1 categorie
Biti
Gigel este pasionat de informatica, si mai ales de cifrele 0 si 1; asa de mult, incat a atribuit
fiecarui din cei 2N prieteni ai lui cate o eticheta, sub forma unui sir de biti de lungime N. Toate
etichetele sunt distincte intre ele.
Gigel s-a gandit intr-o zi ca vrea sa construiasca o eticheta pentru el insusi, de lungime cat mai
mica, care sa contina o singura data, ca o subsecventa, fiecare din cele 2N etichete ale prietenilor
lui.
Cerinta
Scrieti un program care determina eticheta lui Gigel, de lungime minima.
Date de Intrare
Pe prima linie a fisierului de intrare biti.in se va gasi numarul N
Date de Iesire
Pe prima linie a fisierului de iesire biti.out se va gasi lungimea sirului. Pe a doua linie se va afisa
un sir de biti 0 sau 1 care vor reprezenta eticheta gasita.
Restrictii si precizari
1 ≤ N ≤ 20
Daca exista mai multe solutii de lungime minima, se va afisa cea minima din punct de
vedere lexicografic
Exemplu
biti.in biti.out
10
3
0001011100
Trebuie sa te autentifici pentru a trimite solutii. Click aici
Indicii de rezolvare
Traseu
Gigel s-a mutat intr-un oras nou! Pentru a se familiariza cu noile imprejurimi a cumparat harta
orasului si a observat ca este alcatuita din M strazi de diferite lungimi, cu sens unic si N
intersectii de strazi. Gigel a luat harta si a inceput sa alcauiasca un traseu care porneste dintr-o
intersectie anume, trece prin fiecare strada cel putin o data, si revine in intersectia de unde a
pornit. Desi dorinta lui de explorare este mare, conditia lui fizica nu este tocmai buna, astfel ca
vrea sa gasesasca un traseu in care suma lungimilor strazilor parcurse este minima.
Cerinta
Scrieti un program care gaseste un traseu de lungime minima in orasul lui Gigel.
Date de intrare
Pe prima linie a fisierului traseu.in se gasesc numerele N si M separate prin cate un spatiu. Pe
urmatoarele M linii se vor gasi triplete de numere i j k cu semnificatia ca exista o strada de la
intersectia cu numar i la intersectia cu numar j de lungime k.
Date de iesire
Pe prima linie din fisierul traseu.out se va afisa un singur numar natural reprezentand lungimea
minima a traseului lui Gigel.
Restrictii si precizari
1 ≤ N ≤ 60
Lungimile strazilor sunt numere naturale din intervalul [1, 10 000]
Daca intre doua intersectii i si j exista o strada, atunci cu singuranta nu va exista o strada
si intre intersectiile j si i
Se garanteaza ca exista cel putin un traseu in oras care trece prin fiecare strada cel putin o
data si incepe si se termina in aceeasi intersectie
Exemplu
traseu.in traseu.out
68
123
231
312
144 28
462
615
451
516
Explicatii
Traseul ales este: (1,2,3,1,4,6,1,4,5,1).
Evaluatorul infoarena
Documentatie
o Wiki
o Sintaxa Textile
o Macro-uri
o Conventii de formatare
Pentru utilizatori
o Tutorial
o Tutorial articole
o Concursuri virtuale
o Evaluatorul
o Trimiterea solutiilor
o Monitorul
o Borderouri
o Profil
o Rating
Pentru propunatori
o Editare de probleme
o Ghid evaluator
o Arhiva educationala
o Gruparea testelor
Pentru administratori
... este responsabil de evaluarea solutiilor trimise de utilizator.
Compilatoare folosite
Iata lista oficiala de compilatoare folosite de evaluatorul infoarena:
Compilator si Comanda de Extensie
versiune compilare implicita
gcc -Wall -O2
GNU GCC 4.4.3 c
-static … -lm
g++ -Wall -O2
GNU G++ 4.4.3 cpp
-static … -lm
FreePascal
fpc -O2 -Xs … pas
Compiler 2.4.0
Mesaje de evaluare
Pentru cei care nu sunt familiari cu sistemele unix sau sunt incepatori in programare, multe
dintre mesajele evaluatorului pot parea oarecum criptice.
Eroare de sistem: Daca ai obtinut aceast mesaj te rugam sa ne contactezi, preferabil pe
forum. Te rugam sa mentionezi si id-ul job-ului.
OK: Totul a functionat perfect.
Memory limit exceeded: Ai depasit limita de memorie. Majoritatea problemelor au o
limita de 64 de mega, pe care noi o consideram destul de generoasa.
Time limit exceeded: Programul tau a depasit limita de timp. Asta inseamna ca programul
tau nu este destul de rapid.
Wall time limit exceeded: Evaluarea a durat prea mult si a fost abandonata. Evaluatorul
infoarena masoara doar timpul folosit de programul tau pentru a determina daca iti da
TLE, dar exista si o limita fata de "ceasul de perete". Acest mesaj poti sa il obtii daca faci
sleep, scanf de la stdin si alte functii care stau degeaba fara sa consume efectiv
procesorul.
Blocked system call: Ai accesat o functie la care nu ai access. Nu ar trebui sa primesti
aceasta functie decat daca incerci explicit sa faci ceva interzis.
Killed by signal: Cea mai frecventa eroare cand ai un bug in program. Cand un program
incalca anumite conventii in UNIX acel program primeste un "semnal" care de cele mai
multe ori il opreste. Cateva semnale comune:
o 11(SIGSEGV): Segmentation fault. Asta in 99% din cazuri inseamna ca ai
probleme cu accesul la memorie. Ai iesit din limitele unui vector, ai facut stack
overflow, etc.
o 8(SIGFPE): Floating point error. Cauzat cel mai frecvent de impartiri la 0.
Non-zero exit status: Programul tau a returnat o valoare diferita de 0. Cel mai probabil ai
uitat return 0; sau ceva similar. Poti primi acest mesaj si in loc de mesajul "Killed by
signal": verifica si dupa erorile mentionate deasupra.
Evaluatoarele problemelor iti vor da si ele un mesaj scurt, cel mai frecvent ceva de genul "OK"
sau "Wrong Answer", dar unii propunatorii au umor :).
Troubleshooting
Pentru programatorii in Borland C/Pascal este important de tinut minte ca evaluatorul infoarena
este un mediu foarte diferit fata de dos. Cateva erori comune si cum pot fi rezolvate
Pe infoarena se face I/O din fisiere, nu de la stdin, stdout. Daca faci scanf de la stdin vezi
obtine cel mai probabil "Wall time limit exceeded" (vezi mai sus) iar daca faci printf la
stdout rezultatul tau va fi ignorat.
tipul int din GCC este pe 32 de biti, nu 16 ca in Borland C/C++, char - 8 biti, short - 16
biti, long - 32, long long - 64
folositi sprintf in loc de itoa sau ltoa.
programul de evaluare ruleaza pe un sistem de operare UNIX. Folositi "\n" pentru
terminarea liniei curente, nu "\r\n"
aveti grija ca functia main sa fie de tip int si sa intoarca 0 (return 0;)
nu folositi librarii dependente de sistemul de operare (ex. dos.h, graphics.h in C sau dos,
crt, graph in pascal). Aceste librarii nu sunt necesare pentru a rezolva problemele de pe
infoarena.
nu folositi modificatorii far, huge, _huge, __huge pentru ca nu exista in GCC. De
asemenea, nu exista nici functiile care folosesc aceste tipuri de date (de ex. farmalloc,
farfree etc.) si nici conceptul de memory model (tiny, small, medium, large, huge). De
toate acestea nu mai e nevoie intrucat puteti avea acces la toata memoria prin