Sunteți pe pagina 1din 17

Arbori Indexati Binar

(Categoria Structuri de date, autor Giurgea Mihnea)

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

Algoritmi de "baleiere" (line sweeping)


Folosind cunostinte generale de geometrie analitica se poate obtine un algoritm O(N2) dar acesta
nu se va incadra in limita de timp.
Pentru rezolvarea acestei probleme vom folosi o tehnica cunoscuta sub numele de "baleiere"
(sweeping) care este comuna multor algoritmi de geometrie computationala. In baleiere, o
dreapta de baleiere verticala, imaginara, traverseaza multimea obiectelor geometrice, de obicei
de la stanga la Baleierea ofera o metoda pentru ordonarea obiectelor dreapta. geometrice,
plasandu-le intr-o structura de date, pentru obtinerea relatiilor dintre ele.
Algoritmii de baleiere gestioneaza doua multimi de date:
1. Starea liniei de baleiere da relatia dintre obiectele intersectate de linia de baleiere
2. Lista punct-eveniment este o secventa de coordonate x, ordonate de la stanga la dreapta
de obicei, care definesc pozitiile de oprire ale dreptei de baleiere; fiecare astfel de pozitie
de oprire se numeste punct eveniment; numai in punctele eveniment se intalnesc
modificari ale starii liniei de baleiere; pentru unii algoritmi, lista punct-eveniment este
determinata dinamic in timpul executiei algoritmului.
Pentru a rezolva problema, vom deplasa o dreapta de baleiere verticala, imaginara de la stanga la
dreapta. Lista punct-eveniment va contine capetele segmentelor orizontale, ce fel de tip sunt (cap
stanga sau cap dreapta) si segmentele verticale. Pe masura ce ne deplasam de la stanga la dreapta
vom efectua urmatoarele operatii:
 cand intalnim un capat stang, inseram capatul in starile dreptei de baleiere;
 cand intalnim un capat drept, stergem capatul din starile dreptei de baleiere;
 cand intalnim un segment vertical, numarul de intersectii ale acestui segment cu alte
segmente orizontale va fi dat de numarul capetelor de intervale care se afla in starile
dreptei de baleiere cuprinse intre coordonatele y ale segmentului vertical.
Astfel, starile dreptei de baleiere sunt o structura de date pentru care avem nevoie de urmatoarele
operatii:
 INSEREAZA( y ) : insereaza capatul y;
 STERGE( y ) : sterge capatul y;
 INTEROGARE( y1, y2 ) : intoarce numarul de capete cuprinse in intervalul [y1, y2].
Fie MAXC valoarea maxima a coordonatelor capetelor de segmente. Folosind un vector pentru a
implementa aceste operatiile descrise mai sus vom obtine o complexitate O(1) pentru primele
doua operatii si O(MAXC) va fi pentru cea de-a treia. Astfel, complexitatea O(N*MAXC) in
cazul cel mai defavorabil. Putem comprima spatiul [0...MAXC] observand ca doar maxim N din
valori din acest interval conteaza, si anume capetele segmentelor orizontale, astfel reducand a
treia operatie la O(N), dar algoritmul va avea complexitatea O(N2), ceea ce nu aduce nici o
imbunatatire fata de algoritmul trivial.
Aceasta situatie ne indeamna sa cautam o structura de date mai eficienta. O prima varianta ar fi
impartirea vectorului in bucati de sqrt(N) reducand complexitatea totala la O(N*√N). In
continuare vom prezenta o structura de date care ofera o complexitate logaritmica pentru
operatiile descrise mai sus.

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.

Operatii efectuate asupra unui arbore de intervale:


Asupra unui arbore de intervale se pot face doua operatii semnificative: actualizarea, respectiv
interogarea unui interval.
Actualizarea unui interval intr-un arbore de intervale
Vom prezenta pseudocodul unei proceduri recursive care insereaza un interval [a, b] intr-un
arbore de intervale T(st,dr) cu radacina in nodul nod. Cea mai eficienta metoda de stocare in
memorie a unui arbore de intervale este sub forma unui vector folosind aceeasi codificare a
nodurilor precum la heap-uri :
neformatat
print?
01.procedura ACTUALIZARE(nod, st, dr, a, b)
02. daca (a <= st) si (dr <= b) atunci
03. modifica structura auxiliara din nod
04. altfel
05. mij = (st + dr) / 2
06. daca (a <= mij) atunci
07. ACTUALIZARE(2 * nod, st, mij, a, b)
08. daca (b > mij) atunci
09. ACTUALIZARE(2 * nod + 1, mij + 1, dr, a, b)
10. actualizeaza structura auxiliara din nodul nod

Interogarea unui interval intr-un arbore de intervale


Vom prezenta pseudocodul unei proceduri recursive care returneaza informatiile asociate unui
interval [a, b] intr-un arbore de intervale T(st,dr) cu radacina in nodul nod.
neformatat
print?
01.procedura INTEROGARE(nod, st, dr, a, b)
02. daca (a <= st) si (dr <= b) atunci
03. returneaza structura auxiliara din nod
04. altfel
05. mij = (st + dr) / 2
06. daca (a <= mij) atunci
07. INTEROGARE(2 * nod, st, mij, a, b)
08. daca (b > mij) atunci
09. INTEROGARE(2 * nod + 1, mij + 1, dr, a, b)
10. returneaza structura auxiliara din fiul stang combinata cu cea din
fiul drept
Vom demonstra in continuare ca operatiile prezentate mai sus au complexitatea O(log2 N) pentru
un arbore de N intervale. Este posibil ca intr-un nod sa aiba loc apel atat in fiul stang cat si in cel
drept. Acest lucru produce un cost aditional doar prima data cand are loc. Dupa prima "rupere in
doua", oricare astfel de "rupere" nu va aduce cost aditional, deoarece unul din fii va fi mereu
inclus complet in intervalul [a, b]. Cum inaltimea arborelui, pentru N intervale, este [log2N] + 1,
complexitatea operatiilor va fi tot O(log2 N).
Pentru a retine in memorie un arbore de intervale pentru N valori, vom aveam de nevoie de N +
N/2 + N/4 + N/8 + ... = 2*N-1 locatii de memorie (sunt 2*N-1 noduri). Deoarece arborele nu
este complet, trebuie verificat de fiecare data daca fiii unui nod exista in arbore (aceasta
verificare a fost omisa in pseudocodul de mai sus), altfel s-ar incerca accesarea de valori din
vector care nu exista. Daca memorie disponibila in timpul concursului este suficienta, se poate
declara vectorul care retine arborele de intervale de lungime 2K astfel incat 2K ≥ 2*N-1, simuland
astfel un arbore complet si nefiind necesare verificarile mentionate mai sus.
Pentru a rezolva in continuare problema, vom folosi un arbore de intervale pentru a simula in
timp logaritmic operatiile facute inainte pe un vector obisnuit. Astfel, in fiecare nod din arborele
din intervale vom retine cate capete exista in acel interval. Primele doua operatii vor fi
implementate folosind procedura ACTUALIZARE() de mai sus pentru intervalul [y, y] in arborele
T(0, MAXC) si adunand 1, respectiv scazand 1 la fiecare nod actualizat. Cea de-a treia operatie
poate fi realizata folosind procedura INTEROGARE() pe intervalul [y1, y2]. Astfel complexitatea
se reduce la O(N * log2MAXC)Folosind aceeasi tehnica de "comprimare" a coordonatelor se
poate obtine o complexitate  O(N * log2N).
In figura urmatoare este descrisa structura arborelui de intervale, dupa actualizarea pentru
intervalele [2, 2], [6, 6] si [9, 9]. Sunt marcate intervalele care conduc la obtinerea numarului de
segmente intersectate de primul segment vertical, obtinute in urma interogarii pe intervalul [0,
8].

Problema 2 (Preluata de la IOI 1998, Ziua 2)


Se considera N ≤ 50 000 dreptunghiuri in plan, fiecare avand laturile paralele cu axele OX, OY.
Lungimea marginilor (contururilor) reuniunii tuturor dreptunghiurilor se va numi "perimetru". Sa
se calculeze perimetrul celor N dreptunghiuri.
In fisierul drept.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 drept.out.
Timp maxim de executie: 1 secunda/test.
drept.in drept.out Figura
3 44
3883
6 10 12 6
12 4 15 1

Folosind un rationament asemanator ca si la prima problema, constatam necesitatea unui


algoritm de baleiere. Vom descompune problema in doua parti: prima data calculam perimetrul
folosind doar laturile stanga si dreapta ale dreptunghiurilor pentru a calcula perimetrul pe OY;
apoi putem sa rotim dreptunghiurile si folosind aceeasi procedura pt a calcula perimetrul pe OX,
folosind doar laturile sus si jos ale dreptunghiurilor.
Fiecare latura (stanga sau dreapta) va fi un punct eveniment. Sortam laturile crescator dupa
coordonata x si parcurgem de la stanga la dreapta. Cand intalnim o latura stanga adaugam in
starile dreptei de baleiere, intervalul de unitati ocupat de latura pe OY, iar cand intalnim o latura
dreapta, eliminam din starile dreptei de baleiere intervalul de unitati ocupat de latura. Intre
oricare doua puncte eveniment consecutive are loc o modificare a perimetrului total pe OY.
Astfel, dupa fiecare actualizare a starilor dreptei de baleiere se va retine care este numarul de
unitati adaugate pana in prezent (nu se tine cont daca o unitate este adaugata de mai multe ori).
Vom aduna la perimetrul pe OY total de fiecare data, diferenta absoluta intre numarul de unitati
adaugate pana in prezent si valoarea imediat anterioara (dinaintea actualizarii). Asadar, este
necesara o structura de date care se efectueze urmatoarele operatii in timp eficient (preferabil
logaritmic):
 MARCHEAZA(a, b) : adauga intervalul [a, b];
 DEMARCHEAZA(a, b) : elimina intervalul [a, b];
 INTEROGARE() : returneaza numarul total de coordonate adaugate pana in prezent.
Putem folosi un arbore de intervale pentru a obtine o complexitate O(log2 MAXC) sau O(log2 N)
pentru primele doua operatii si O(1) pentru ce-a de treia. In fiecare nod din arbore retinem de
cate ori a fost marcat intervalul respectiv si cate unitati din intervalul respectiv au fost marcate.
Primele doua operatii pot fi implementate folosind procedura ACTUALIZARE() iar a treia
operatie va returna valoarea numarul de unitati care au fost marcate din radacina arborelui de
intervale.
In figura urmatoare este descrisa structura arborelui de intervale, dupa adaugarea intervalelor [3,
8] si [6, 10] (un interval [y1, y2] reprezinta intervalul de unitati [y1, y2 - 1] din arbore).

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.

2. Preluata de la Olimpiada Nationala de Informatica, Polonia 2001


Se considera N ≤ 50 000 puncte in plan de coordonate numere naturale mai mici ca 50 000. Sa se
determine unde se poate aseza un dreptunghi de lungime DX si latime DY astfel incat numarul de
puncte incluse in dreptunghi sa fie maxim.
In fisierul puncte.in se gasesc pe prima linie numerele N, DX si DY. Pe urmatoarele N linii se
gasesc coordonatele punctelor. In fisierul puncte.out se vor gasi cinci numere naturale
reprezentand coordonatele colturilor stanga sus si dreapta jos ale asezarii dreptunghiului si
numarul maxim de puncte din dreptunghi.
Timp maxim de executie: 1 secunda/test.
3. Preluata de la Barajul pentru Lotul National, Romania 2003
Se considera N ≤ 100 000 puncte in plan de coordonate numere naturale mai mici ca 100 000. Sa
se determine unde se pot aseza doua dreptunghiuri de lungime DX si latime DY, fara sa se
intersecteze, astfel incat numarul de puncte incluse in cele doua dreptunghiuri sa fie maxim.
In fisierul puncte2.in se gasesc pe prima linie numerele N, DX si DY. Pe urmatoarele N linii se
gasesc coordonatele punctelor. In fisierul puncte2.out se vor gasi 9 numere naturale reprezentand
coordonatele colturilor stanga sus si dreapta jos ale asezarii primului dreptunghi, respectiv a
celui de-al doilea, cat si numarul maxim de puncte incluse in ambele dreptunghiuri.
Timp maxim de executie: 1 secunda/test.

4. Preluata de la concursul international USACO January Open, 2004


Se considera N ≤ 250 000 dreptunghiuri in plan, fiecare avand laturile paralele cu axele OX, OY,
care nu se intersecteaza si nu se ating, dar pot fi incluse unul in altul. Se numeste "inchisoare" un
dreptunghi inconjurat de alte dreptunghiuri. Sa se determine numarul maxim de dreptunghiuri de
care poate fi inconjurata o "inchisoare" si cate astfel de "inchisori" maxime exista.
In fisierul inchis.in se gaseste pe prima linie numarul N de dreptunghiuri, iar pe fiecare din
urmatoarele N linii cate patru numere naturale mai mici ca 1 000 000 000, reprezentand
coordonatele carteziene ale coltului stanga sus, respectiv dreapta jos ale fiecarui dreptunghi. In
fisierul inchis.out se gasesc doua numere naturale: numarul maxim de dreptunghiuri de care
poate fi inconjurata o "inchisoare" si cate astfel de "inchisori" maxime exista.
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

 Elementele sirului sunt numere intregi distincte cuprinse intre 1 si 1000

 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.

Cum se evalueaza o problema


Mai intai, codul sursa trimis de concurent se compileaza (vezi tabelul de mai jos). Apoi, solutia
se evalueaza: se ruleaza programul compilat pentru diferite date de intrare (teste). In urma
rularii, un program specializat decide daca raspunsul dat de solutia concurentului este corect si
acord un punctaj pe masura.
Fiecare program compilat are dreptul de a rula doar un anumit interval de timp (specificat in
descrierea problemei). in cazul in care timpul de executie este depasit, programul este terminat
automat de sistem. Analog, se pot impune si limite de memorie.
Evaluarea se face intr-un mediu restrictionat. Programele compilate pot citi/scrie fisiere doar
din/in directorul curent si nu au acces la unele functii sistem.

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

Configuratia sistemului de evaluare


 Sistem de operare: Ubuntu 10.04.3 LTS
 Procesor: Intel Pentium® Dual-Core CPU E6500 @ 2.93GHz
 Memorie: 2048 MB RAM

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

S-ar putea să vă placă și