Cod sursa(job #2713513)

Utilizator Casian_doispeChiriac Casian Casian_doispe Data 28 februarie 2021 10:28:26
Problema Arbori de intervale Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.4 kb
#include <fstream>

#define MOD 666013

using namespace std;

ifstream cin ("arbint.in");
ofstream cout ("arbint.out");

/// arbori de intervale
/// se face un vector unde copii ai indicele 2i si 2i+1, i fiind indicele parintelui
/// cand se cauta prop unui interval anume consideram numai intervalele incluse in intervalul dat
/// daca un interval contine info de valoare atunci coboram pe el

/// un nod este caracterizat in cazul nostru printr-o pozitie in vectorul v[] si un interval st-dr, deci la fiecare functie recursiva sunt date aceste valori
/// pentru a descrie nodul curent, si se pleaca din nodul 'cap' care este poz pe v[1]

int v[500009] ;

/// primul pas este updateul in arbore
/// se cauta practic binar locul unde va va fi inserat elemenul curent
/// se face aceasta pentru a retine capabilitatea de a schimba un element de ex daca vrem sa zicem ca v[15] = 500 dar precedent v[15] = 100
/// astfel se compara la fiecare pas cele doua intervale in care este splituit intervalul de pe nodul curent cu indicele elementului care trebuie modificat
/// se alege intervalul in care este indicele elementului si se continua pe acea ramura pana cand intervalul curent consista dintr-un singur element,
/// chiar indicele pe care trebuie sa il schimbam
/// pentru a pastra proprietatiile arborelui, dupa apelul recursiv se updateaza fiecare nod din arbore afectat de schimbarea acelui indice prin acel v[poz] = max(...) ;

void update(int st, int dr, int f, int poz, int a)
{

    /// st si dreapta este rangeul in care updatam
    /// a este valoarea vare o bagam iar f este indicele acestei valori
    /// poz este pozitia in v[] a nodului curent (cand dam update mereu incepem din cap, nodul initial)

    int mij = (st + dr) / 2 ;

    ///cout << st << " " << dr << endl ;

    if(st == dr)
    {

        v[poz] = a ;

        return ;

    }

    if(f > mij)
    {

        update(mij + 1, dr, f, poz * 2 + 1, a) ;

        v[poz] = max(v[poz * 2], v[poz * 2 + 1]) ;

    }
    else
    {

        update(st, mij, f, poz * 2, a) ;

        v[poz] = max(v[poz * 2], v[poz * 2 + 1]) ;

    }

}

/// pentru un query parcurgem arborele si consideram fiecare nod
/// daca nodul curent este complet in afara intervalului care ne intereseaza pe noi atunci returnam o valoare nesemnificativa, 0 in cazul nostru
/// daca nodul curent este complet inauntrul intervalului care ne intereaseaza returnam valoarea sa (de aici vine eficienta algoritmului)
/// altfel returnam ceea ce ne intereseaza dintre copii nodului curent, in cazul nostru maximul dintre cei doi

int query(int st, int dr, int poz, int ST, int DR)
{

    /// daca intervalul curent este complet inauntrul celui cautat returnam val lui
    /// alftel returnam valoarea din el
    /// daca intervalul e off rau ii dam return 0 ;

    if(DR < st || ST > dr)return 0 ;

    if(ST >= st && DR <= dr)return v[poz] ;

    return max(query(st, dr, poz * 2, ST, (ST + DR) / 2), query(st, dr, poz * 2 + 1, (ST + DR) / 2 + 1, DR)) ;

}

int main()
{

    int n, q ;

    cin >> n >> q ;

    for(int f = 1, a ; f <= n ; f ++)
    {

        cin >> a ;

        update(1, n, f, 1, a) ;

    }

    while(q --)
    {

        int cer, a, b ;

        cin >> cer >> a >> b ;

        if(!cer)cout << query(a, b, 1, 1, n) << '\n' ;
            else update(1, n, a, 1, b) ;

    }

    return 0;
}
/// 3 5 6 2