Cod sursa(job #2899316)

Utilizator TindecheTindeche Alexandru Tindeche Data 8 mai 2022 15:06:44
Problema Zeap Scor 10
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 5.03 kb
#include <string.h>
#include <fstream>
#include <set>
#include <queue>
#include <string>
#include <iterator>

using namespace std;

ifstream fin("zeap.in");
ofstream fout("zeap.out");

string input;
set<int> zeap;
/*
 * Setul are elementele ordonate crescator => pentru diferent minima trebuie doar sa calculez
 * diferentele dintre elementele consectutive, iar pentru diferenta maxima voi
 * face diferenta dintre primul si ultimul element
 *
 * Pentru a retine diferentele minime voi folosi un priority queue in care tin minte
 * o pereche formata din diferenta (pe care o pun cu minus ca sa am un min heap)
 * si perechea formata din elementul si cel mai apropiat cu care fac diferenta
 */
priority_queue<pair<int, pair<int, int>>> min_dif; // "sortarea" se face dupa primul element din tuplu, cel mai mare avand prioritate maxima
// deci ca sa il fac de minim trebuie sa pun toate valorile cu minus

int numar (string x)
{
    int nr = 0;
    for (int i = 2; i < x.size(); i++)
    {
        nr = nr * 10 + (x[i] - '0');
    }
    return nr;
}

void insereaza (int x)
{
    if (zeap.find(x) == zeap.end()) // Daca numarul nu este deja in zeap
    {
        // Inseram numarul:
        zeap.insert(x);
        //Daca zeapul contine mai mult de 2 elemente pentru a face diferentele minime, le si calculez
        if (zeap.size() >= 2)
        {
            // Verificam daca zeapul are mai mult de doua elemente ca sa putem sa facem diferentele dintre
            // x si elementele de langa el
            /*
             * Daca sunt mai mult de 2 elemente in zeap, o sa calulez diferenta dintre
             * noul element x si cele mai apropiate 2 elemente si le inserez in priority queue.
             *
             * Voi gasi cele mai apropiate doua elemente folosind un obiect de tip iterator, declarand o var
             * de tip auto pentru a lasa compilatorul sa determine ca este un iterator
             * (imi este lene sa scriu set<int>::iterator i;), iar apoi il folosesc ca sa pargurg multimea
             *
             * Astfel parcurg mutimea prin acest iterator si determin elemtemtul de dinaintea si de dupa x
             */
            auto i = zeap.find(x);
            if (i != zeap.begin())
            {
                i--; // Iau elementul din stanga sa
                min_dif.push(make_pair(-abs(*i - x), make_pair(*i,
                                                               x))); // Bag in queue diferenta urmata de numerele care au dat diferenta
            }

            // Fac acelasi lucru si pentru elementele din dreapta (vad daca x nu este ultimul si fac diferenta)
            i = zeap.find(x);
            i++;
            if (i != zeap.end())
            {
                min_dif.push(make_pair(-abs(*i - x), make_pair(*i, x)));
            }
        }
    }
}

void sterge (int x)
{
    if (zeap.find(x) == zeap.end())
    {
        fout << "-1\n";
        return;
    }
    auto i = zeap.find(x);
    auto right = i;
    right++;
    // Daca este primul sau ultimul element il sterg fara sa imi fac griji ca afectez vreo diferenta
    if (i == zeap.begin() || right == zeap.end()) // (1)
        zeap.erase(x);
    else
    {
        // Gasim si elementul din stanga pentru ca stim ca x nu este primul element
        auto left = i;
        left--;
        // Daca nu este primul element si nici ultimul (nu ne putem baza pe (1) pentru ca este sau intre conditii)
        if ( right != zeap.end() && i != zeap.begin())
        {
            // Trebuie sa introducem diferenta dintre elementul din dreapta si cel din stanga lui x,
            // pentru ca acum ele ajung unul langa altul
            min_dif.push(make_pair(-abs(*right - *left), make_pair(*left, *right)));;
        }
        zeap.erase(x);
    }
}

void cauta (int x)
{
    if (zeap.find(x) == zeap.end())
    {
        fout << "0\n";
        return;
    }
    fout << "1\n";
}

void minim()
{
    if(zeap.size() < 2)
    {
        fout << "-1\n";
        return;
    }
    // Trebuie sa scoatem toate diferentele dintre 2 elemente consecutive dintre care unul sau ambele
    // nu mai sunt in multime pentru a gasi prima diferenta valida (care este si cea mai mica)
    while(zeap.find(min_dif.top().second.first) == zeap.end()
            || zeap.find(min_dif.top().second.second) == zeap.end())
        min_dif.pop();
    fout << -min_dif.top().first << '\n';
}

void maxim()
{
    if(zeap.size() < 2)
    {
        fout << "-1\n";
        return;
    }
    auto left = zeap.begin();
    auto right = zeap.end();
    right--;
    fout << *right - *left << '\n';
}

int main ()
{
    int x;
    while (getline(fin, input))
    {
        if (input[0] == 'I')
        {
            x = numar(input); // Aici creem numarul care trebuie inserat
            insereaza(x);
        } else if (input[0] == 'S')
        {
            x = numar(input);
            sterge(x);
        } else if (input[0] == 'C')
        {
            x = numar(input);
            cauta(x);
        } else if(input == "MAX")
        {
            minim();
        } else if(input == "MIN")
        {
            maxim();
        }
    }
    return 0;
}