# PBinfo #3468 – weekend – Rezolvare C++

Sursa: Codul lui Andrei
Limbaj: C++
Autor rezolvare: deivid

## Enunț

În acest weekend tocmai s-au pus în vânzare bilete pentru concertul celui mai în vogă artist. Cum acesta este extrem de popular, un număr de n persoane s-au așezat la coadă la casa de bilete. Pentru simplitate, prima persoană așezată la coadă va avea indicele 1, a doua va avea indicele 2 și așa mai departe.

Deoarece statul la coadă este extrem de plictisitor, fiecare om a început să numere câte persoane mai scunde decât el se află în fața sa. Se cunoaște că înălțimile oamenilor sunt reprezentate cu numere naturale nenule.

Din lipsă de imaginație, oamenii care stau la coadă nu au reușit sa ducă jocul până la capăt, așa că o vom face noi. Cunoscând câte persoane mai scunde decât el are în față fiecare om care stă la coadă, se cere să se determine înălțimea fiecărui om din șir.

Dacă există mai multe soluții valide, se cere afișată soluția minim lexicografică. Dacă există două șiruri valide de înălțimi ale celor n persoane A1, A2 ,…, An și B1, B2, …, Bn spunem că șirul A este mai mic lexicografic decât B dacă există un număr natural i mai mic sau egal decât n astfel încât Ai < Bi și Aj = Bj, oricare ar fi j = 1..i-1.

Cerința
Fiind dat șirul inițial de observații ale oamenilor care stau la coadă, să se reconstruiască șirul minim lexicografic care poate reprezenta înălțimile acestora.

Date de intrare
Fișierul de intrare weekend.in va avea pe prima linie numărul n. Pe linia a doua se va afla un șir de n numere naturale despărțite printr-un spațiu, valoarea aflată pe poziția i semnificând numărul de persoane strict mai scunde decât persoana i și cu indice mai mic decât i.

Date de ieșire
În fișierul de ieșire weekend.out se va afișa șirul înălțimilor. Pe linia a i-a din fișierul de ieșire se va afla înălțimea persoanei cu indicele i.

Restricții și precizări

Se garantează că setul de date este corect și va exista mereu cel puțin o soluție.
Două sau mai multe persoane NU pot avea aceeași înălțime.
1 ≤ N ≤ 200.000
Pentru 40% din teste, N <= 5.000

Exemplu:
weekend.in

4
0 1 1 0
weekend.out

2
4
3
1
Explicație
Observăm că acesta este cel mai mic șir lexicografic care satisface șirul de observații din input. O altă soluție ar fi fost șirul 2 5 3 1, dar acesta este mai mare lexicografic.

## Cod sursă C++

```cpp
/**
  *  Worg
  */
#include <vector>
#include <fstream>
#include <cassert>
#include <algorithm>
struct stree_node {
    int min_value, lazy_add;
    stree_node() : min_value(0), lazy_add(0) {
    }
};
void build_stree(int node, int left, int right, std::vector<stree_node> &stree, std::vector<int> &v) {
    if (left == right) {
        stree[node].min_value = v[left];
        stree[node].lazy_add = 0;
        return;
    }
    int mid = (left + right) / 2, left_son = node * 2, right_son = left_son + 1;
    build_stree(left_son, left, mid, stree, v);
    build_stree(right_son, mid + 1, right, stree, v);
    stree[node].min_value = std::min(stree[left_son].min_value, stree[right_son].min_value);
    stree[node].lazy_add = 0;
}
int update(int node, int left, int right, int value, std::vector<stree_node> &stree, std::vector<int> &sol) {
    //  Lazy Update
    int mid = (left + right) / 2, left_son = node * 2, right_son = left_son + 1;
    if (left != right) {
        stree[left_son].min_value += stree[node].lazy_add;
        stree[left_son].lazy_add += stree[node].lazy_add;
        stree[right_son].min_value += stree[node].lazy_add;
        stree[right_son].lazy_add += stree[node].lazy_add;
        stree[node].lazy_add = 0;
    }
    //  Done
    if (left == right) {
        sol[left] = value;
        stree[node].min_value = (int)stree.size();
        return left;
    }
    int return_value;
    if (stree[right_son].min_value <= stree[left_son].min_value) {
        return_value = update(right_son, mid + 1, right, value, stree, sol);
    } else {
        return_value = update(left_son, left, mid, value, stree, sol);
    }
    stree[node].min_value = std::min(stree[left_son].min_value, stree[right_son].min_value);
    return return_value;
}
void decrease(int node, int left, int right, int first, int last, std::vector<stree_node> &stree) {
    //  Lazy Update
    if (first > last) return;
    int mid = (left + right) / 2, left_son = node * 2, right_son = left_son + 1;
    if (left != right) {
        stree[left_son].min_value += stree[node].lazy_add;
        stree[left_son].lazy_add += stree[node].lazy_add;
        stree[right_son].min_value += stree[node].lazy_add;
        stree[right_son].lazy_add += stree[node].lazy_add;
        stree[node].lazy_add = 0;
    }
    //  Done
    if (first <= left && right <= last) {
        stree[node].min_value -= 1;
        stree[node].lazy_add -= 1;
        return;
    }
    if (first <= mid) {
        decrease(left_son, left, mid, first, last, stree);
    }
    if (mid + 1 <= last) {
        decrease(right_son, mid + 1, right, first, last, stree);
    }
    stree[node].min_value = std::min(stree[left_son].min_value, stree[right_son].min_value);
}
void solve() {
    std::ifstream fin("weekend.in");
    std::ofstream fout("weekend.out");
    int n; fin >> n;
    std::vector<int> v(n);
    bool flag = false;
    for (int i = 0; i < n; i++) {
        fin >> v[i];
        if (v[i] > i) {
            flag = true;
        }
    }
    assert(flag == false);
    std::vector<stree_node> stree(4 * n);
    build_stree(1, 0, n - 1, stree, v);
    std::vector<int> sol(n, 0);
    for (int step = 1; step <= n; step++) {
        int where = update(1, 0, n - 1, step, stree, sol);
        //std::cout << "where = " << where << "\n";
        decrease(1, 0, n - 1, where + 1, n - 1, stree);
    }
    for (int i = 0; i < n; i++) {
        fout << sol[i] << "\n";
    }
}
int main() {
    solve();
    return 0;
}
```

## Resurse

- [Pagina originală](https://codulluiandrei.ro/rezolvari/pbinfo/3468)
- [Sursa C++](https://codulluiandrei.ro/rezolvari/pbinfo/3468/cod.cpp)
- [Sursa pe GitHub](https://raw.githubusercontent.com/codulluiandrei/pbinfo/main/pbinfo-3468/main.cpp)
- [Cursuri de informatică pentru BAC](https://codulluiandrei.ro/academia/info-curs/pachet-cpp/)
