Cod sursa(job #2924222)

Utilizator XXMihaiXX969Gherghinescu Mihai Andrei XXMihaiXX969 Data 27 septembrie 2022 14:48:27
Problema Arbori de intervale Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.9 kb
#include <bits/stdc++.h>

using namespace std;

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

const int MIN_VALUE = -1e6;

void buildTree(int v[], int tree[], int left, int right, int poz)
{
    if (left == right)
    {
        //we reached a leaf
        tree[poz] = v[left];
        return;
    }
    int mid = left + (right - left) / 2;
    
    //build left child
    buildTree(v, tree, left, mid, 2 * poz + 1);
    //build right child
    buildTree(v, tree, mid + 1, right, 2 * poz + 2);
    //get maximum in parent node
    tree[poz] = max(tree[2 * poz + 1], tree[2 * poz + 2]);
}

void updateTree(int v[], int tree[],
    int left, int right, int poz, int updatePoz, int val)
{
    if (left == right)
    {
        //we reached a leaf
        //cand ajungem la frunza, ajungem fix
        //la frunza care contine pozitia care ne intereseaza
        //de ce?
        //mereu mergem pe intervalul unde este pozitia noastra
        //pana cand ajungem la intervalul cu o singura pozitie
        tree[poz] = val;
        return;
    }
    //just follow up with the updates
    int mid = left + (right - left) / 2;
    
    //check what part needs to be updated
    if (updatePoz <= mid)
    {
        //build left child
        updateTree(v, tree, left, mid, 2 * poz + 1,
            updatePoz, val);
    }
    else
    {
        //build right child
        updateTree(v, tree, mid + 1, right, 2 * poz + 2,
            updatePoz, val);
    }
    //get maximum in parent node
    tree[poz] = max(tree[2 * poz + 1], tree[2 * poz + 2]);
}

int treeRangeMinimumQuerry(int v[], int tree[], 
    int left, int right, int poz, int leftQuery, int rightQuery)
{
    // total overlap 
    //EX: daca ai intervalul [0,5]
    //tu ai ajuns la [0,4]
    //[0,4] e inclus in [0,5] deci poti sa iei direct minimul
    if (leftQuery <= left && rightQuery >= right)
        return tree[poz];
    
    // no overlap
    //EX: ai intervalul [2,10]
    // iar tu ai ajuns la [1, 1]
    // 1 nu e inclus in intervalul tau
    // deci nu te intereseaza
    // returnezi o valoare care nu poate fi rezultat
    if (leftQuery > right || rightQuery < left)
        return MIN_VALUE;
    
    // partial overlap
    //EX: daca ai intervalul [0, 6]
    // tu ai ajuns la [3, 7]
    // [3, 7]  nu e inclus in intervalul tau este,
    // dar [0, 3] este, la fel si in dreapta [4, 6] este
    // cauti in stanga in [0, 3]  si in dreapta in [4, 7]
    int mid = left + (right - left) / 2;
    
    return max(treeRangeMinimumQuerry(v, tree, left,
        mid, 2 * poz + 1, leftQuery, rightQuery),
        treeRangeMinimumQuerry(v, tree, mid + 1,
        right, 2 * poz + 2, leftQuery, rightQuery));
}

int calculateTreeDimension(int n)
{
    //pentru fiecare pereche de numere ai cate un rezultat
    //ar veni practic n + n / 2 + n / 4 + ... 1
    // suma progresiei geometrice este egala cu
    // 2 ^ (nr termeni) - 1
    // daca n e putere de 2 o sa acoperi tot tree-ul
    // deci numarul de termeni e log2(n) + 1
    // daca nu trebuie creat un nivel in plus cu frunze cu val
    // maxima, ca sa ai unde pune toate valorile
    int lg = log2(n);
    
    if ((1 << lg) == n)
        return (1 << (lg + 1)) - 1;
    else
        return (1 << (lg + 2)) - 1;
}

int main()
{
    int n, m;
    in >> n >> m;
    int v[n];
    for (int i = 0; i < n; i++)
        in >> v[i];
    
    int treeSize = calculateTreeDimension(n);
    int tree[treeSize];
    for (int i = 0; i < treeSize; i++)
        tree[i] = MIN_VALUE;

    buildTree(v, tree, 0, n - 1, 0);
    
    while (m--)
    {
        int c, x, y;
        in >> c >> x >> y;
        x--;
        y--;
        if (c == 0)
            out << treeRangeMinimumQuerry(v, tree, 0, n - 1, 0,
                x, y) << endl;
        else
            updateTree(v, tree, 0, n - 1, 0, x, y + 1);
    }
    
    return 0;
}