Cod sursa(job #3252277)

Utilizator MateicostiGoidan Matei-Constantin Mateicosti Data 28 octombrie 2024 23:48:41
Problema Arbori de intervale Scor 40
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.03 kb
/* Arbori de inervale
 *
 * 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];
 *
 * Fiecare nod contine valoarea maxima din intervalul [st, dr] din vectorulA;
 *
 * Este folosit un HEAP pentru a stoca in memorie.
*/

#include <algorithm>
#include <fstream>
#include <iostream>
#include <vector>

std::ifstream fin("arbint.in");
std::ofstream fout("arbint.out");

struct Node {
  int minimum, maximum;
  long long valMax;
};

int n, m;
std::vector<int> intervallTree;
std::vector<long long> vectorA;

// Preluarea valorii maxime dintr-un nod
int interogate(int poz, int minimum, int maximum, int intervalA,
               int intervalB) {
  if (intervalA <= minimum && maximum <= intervalB) {
    // Verificam daca am ajuns in intervalul corect (nodul)
    return intervallTree[poz];
  } else {
    // Daca nu coboram mai mult in arbore
    int leftVal = 0, rightVal = 0;
    int middle = (minimum + maximum) / 2;

    // Trecem pe nodul din stanga 
    if (intervalA <= middle) {
      leftVal = interogate(2 * poz, minimum, middle, intervalA, intervalB);
    }

    // Trecem pe nodul din dreapta 
    if (intervalB > middle) {
      rightVal =
          interogate(2 * poz + 1, middle + 1, maximum, intervalA, intervalB);
    }

    return std::max(leftVal, rightVal);
  }
}

// Actualizam valorile din arbore folosind un heap
void update(int a, int poz, int minimum, int maximum, int intervalA,
            int intervalB) {
  if (intervalA <= minimum && maximum <= intervalB) {
    // Verificam daca am ajuns la nodurile frunza
    intervallTree[poz] = a;
  } else {
    // Daca nu calculam urmatoarea pozitie dupa care ar trebui sa mergem in heap
    int middle = (minimum + maximum) / 2;

    // Trecem pe nodul din stanga
    if (intervalA <= middle) {
      update(a, 2 * poz, minimum, middle, intervalA, intervalB);
    }

    // Trecem pe nodul din dreapta 
    if (intervalB > middle) {
      update(a, 2 * poz + 1, middle + 1, maximum, intervalA, intervalB);
    }

    // La intoarcerea recursiva actualizam toate nodurile parcurse in cazul in
    // care valoare maxima se schimba
    intervallTree[poz] =
        std::max(intervallTree[2 * poz], intervallTree[2 * poz + 1]);
  }
}

int main(int argc, char *argv[]) {
  // Verificam daca fisierul se poate deschide
  if (!fin.is_open()) {
    std::cout << "ERROR: File failed to open!";
  }

  // Citirea vectorului
  fin >> n >> m;
  vectorA.resize(n + 1);
  for (int i = 1; i <= n; i++) {
    int x;
    fin >> x;
    vectorA[i] = x;
  }

  // Creem arborele de intervale
  intervallTree.resize(2 * n);
  for (int i = 1; i <= n; i++) {
    update(vectorA[i], 1, 1, n, i, i);
  }

  // Citirea operatilor
  for (int i = 0; i < m; i++) {
    int op, a, b;

    fin >> op >> a >> b;
    if (op == 0) {
      fout << interogate(1, 1, n, a, b) << '\n';
    } else if (op == 1) {
      update(b, 1, 1, n, a, a);
    }
  }

  fin.close();
  fout.close();

  return 0;
}