Cod sursa(job #1672496)

Utilizator stoianmihailStoian Mihail stoianmihail Data 2 aprilie 2016 19:52:23
Problema Arbori de intervale Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 3.7 kb
#include <stdio.h>

#define Nadejde 131072

/** Implementarea arborilor de intervale:
 *                   (1)
                 [1,     5]
            (2) /          \ (3)
          [1, 3]           [4, 5]
       (4)/    \ (5)   (6) /    \ (7)
     [1, 2]    [3, 3] [4, 4]    [5, 5]
 (8) /    \ (9)
[1, 1]    [2, 2]

*  Precizari:
*  * Fiecare nod "u" are 2 fii: nodul 2u, respectiv 2u + 1.

**************************************************************************
*  Functia update: Trebuie sa modificam pozitia "pos" in valoarea "val":
* Exemplu: pos = 2, val = 3.

*  Vom pleca din radacina, reprezentata de nodul 1 -> [1, 5].
*  In acest moment, ne intereseaza care dintre fii ei contine pozitia 2.
*  Observam ca fiul stang [1, 3] contine pozitia 2, deci vom avansa pe partea stanga prin nodul 2.
*  Am ajuns in nodul 2. Cautam, analog, care dintre fii sai contine  pozitia 2 (fiul stang - nodul 4).
*  In nodul 4 -> [1, 2], mergem catre intervalul de lungime 1, [2, 2] continut de nodul 9.
*  Resetam valoarea continuta de acest nod.

*  Pentru a reconstitui arborele de intervale, va trebui sa ne intoarcem pe unde am venit, reinitializand
* maximul din fiecare nod.
*  Drumul nostru a fost: 1, 2, 4.
*  Pentru fiecare astfel de nod, ne vom uita la fiul stang si la fiul drept pentru a vedea daca s-a imbunatatit
* maximul curent.
***************************************************************************

***************************************************************************
*  Functia query: Ne intereseaza maximul din intervalul [a, b].
* Exemplu: a = 2, b = 4.

*  Vom pleca, exact ca la Update, din radacina.
*  In momentul in care suntem intr-un nod "u" urmarim 3 lucruri:
*  I) Daca intervalul reprezentat este inclus in [a, b],
*  -> Reactualizam raspunsul.
*  II) Daca intervalul reprezentat de fiul stang se intersecteaza cu [a, b],
*  -> Vom intra in fiul stang, cautand actualizari ale raspunsului.
*  III) Daca intervalul reprezentat de fiul drept se intersecteaza cu [a, b],
*  -> Vom intra in fiul drept, cautand actualizari ale raspunsului.
***************************************************************************
*  Multumim Doamne!
**/

int N, M;
int tree[2 * Nadejde];
int max;

/** max(X, Y). **/
int MAX(int X, int Y) {
  return X > Y ? X : Y;
}

/** Updateaza arborele in nodul "node" -> [left, right], pentru pozitia "pos" si valoarea "val". **/
void update(int node, int left, int right, int pos, int val) {
  if (left == right) {
    tree[node] = val;
    return;
  }

  int mid = (left + right) >> 1;

  if (pos <= mid) {
    update(2 * node, left, mid, pos, val);
  } else {
    update(2 * node + 1, mid + 1, right, pos, val);
  }
  tree[node] = MAX(tree[2 * node], tree[2 * node + 1]);
}

/** Obtine o informatie din nodul "node" -> [left, right], pentru intervalul [a, b]. **/
void query(int node, int left, int right, int a, int b) {
  if ((a <= left) && (right <= b)) {
    max = MAX(max, tree[node]);
    return;
  }

  int mid = (left + right) >> 1;

  if (a <= mid) {
    query(2 * node, left, mid, a, b);
  }
  if (b > mid) {
    query(2 * node + 1, mid + 1, right, a, b);
  }
}

int main(void) {
  int i, val, task, a, b;
  FILE *f = fopen("arbint.in", "r");

  /* Citirea datelor si construirea arborelui. */
  fscanf(f, "%d %d", &N, &M);
  for (i = 1; i <= N; i++) {
    fscanf(f, "%d", &val);
    update(1, 1, N, i, val);
  }

  /* Citirea intrebarilor si afisarea raspunsurilor. */
  freopen("arbint.out", "w", stdout);
  while (M) {
    fscanf(f, "%d %d %d", &task, &a, &b);
    if (task == 0) {
      max = 0;
      query(1, 1, N, a, b);
      fprintf(stdout, "%d\n", max);
    } else {
      update(1, 1, N, a, b);
    }
    M--;
  }
  fclose(f);
  fclose(stdout);

  /// Multumim Doamne!
  puts("Doamne ajuta!");
  return 0;
}