Cod sursa(job #1322512)

Utilizator AlexandruValeanuAlexandru Valeanu AlexandruValeanu Data 20 ianuarie 2015 09:07:48
Problema Hashuri Scor 70
Compilator cpp Status done
Runda Arhiva educationala Marime 4.87 kb
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <bits/stdc++.h>

using namespace std;

/**
 * Metodă: folosim un singur vector mare în care ne facem toate alocările,
 * pentru a evita alocări dinamice. Un element constă din valoarea propriu-
 * zisă și pointeri pentru fiecare nivel. Nivelul elementului nu este stocat
 * nicăieri, de aceea nici mărimea fiecărei înregistrări în vector nu poate fi
 * aflată explicit. Structura suportă ștergeri, dar memoria consumată nu mai
 * este eliberată.
 *
 * La începutul și la sfârșitul listei punem -INFINITY, de nivel MAX_LEVEL,
 * respectiv +INFINITY, fără pointeri.
 *
 * Exemplu: dacă inserăm elementele 17 (nivel 3) și 5 (nivel 2), presupunând
 * că MAX_LEVEL = 5, conținutul vectorului va fi (cu barele inserate pentru
 * claritate):
 *
 * -INF  11  11   7   6   6 | +INF |  17   6   6   6 |  5   7   7
 *    0   1   2   3   4   5 |    6 |   7   8   9  10 | 11  12  13
 */

#define MAX_LEVEL 20         // 2^MAX_LEVEL aproximativ egal cu TRIAL_SIZE
#define TRIAL_SIZE 1000000   // numărul de elemente căutate
#define MAX_BUF 3100000      // mărimea vectorului prealocat
#define INFINITY 2000000000
#define MAX_VALUE 2000000    // folosit la testare

int sl[MAX_BUF];             // zona de memorie prealocată
int level;                   // nivelul maxim al oricărui element
int bufPtr;                  // primul slot nealocat
int update[MAX_LEVEL];       // folosit în timpul inserării
char check[MAX_VALUE];       // folosit în timpul testării
long long t0;

void init() {
  // Capul listei are valoarea -INF și MAX_LEVEL pointeri către coada listei
  // Coada listei are valoarea +INF și zero pointeri
  sl[0] = -INFINITY;
  sl[MAX_LEVEL + 1] = INFINITY;
  for (int i = 0; i < MAX_LEVEL; i++) {
    sl[i + 1] = MAX_LEVEL + 1;
  }
  bufPtr = MAX_LEVEL + 2;
  level = 1;
}

int randomLevel() {
  unsigned r = rand() & ~(1 << (MAX_LEVEL - 1));
  int l = 1;
  while (r & 1) {
    l++;
    r >>= 1;
  }
  return l;
}

void insert(int x) {
  int pos = 0;
  for (int l = level - 1; l >= 0; l--) {
    while (sl[sl[pos + l + 1]] < x) {
      pos = sl[pos + l + 1];
    }
    update[l] = pos;
  }
  pos = sl[pos + 1];

  if (sl[pos] != x) { // nu permitem duplicate
    int newLevel = randomLevel();
    if (newLevel > level) {
      for (int l = level; l < newLevel; l++) {
        update[l] = 0;
      }
      level = newLevel;
    }

    sl[bufPtr] = x;
    for (int l = 0; l < newLevel; l++) {
      sl[bufPtr + l + 1] = sl[update[l] + l + 1];
      sl[update[l] + l + 1] = bufPtr;
    }
    bufPtr += newLevel + 1;
    assert(bufPtr < MAX_BUF);
  }
}

int search (int x) {
  int pos = 0;
  for (int l = level - 1; l >= 0; l--) {
    while (sl[sl[pos + l + 1]] < x) {
      pos = sl[pos + l + 1];
    }
  }
  pos = sl[pos + 1];
  return sl[pos] == x;
}

void erase(int x) {
  int pos = 0;
  for (int l = level - 1; l >= 0; l--) {
    while (sl[sl[pos + l + 1]] < x) {
      pos = sl[pos + l + 1];
    }
    update[l] = pos;
  }
  pos = sl[pos + 1];

  if (sl[pos] == x) {
    // Refacem acei pointeri care pointează la pos (restul trec pe deasupra noastră).
    int l = 0;
    while ((l < MAX_LEVEL) && sl[update[l] + l + 1] == pos) {
      sl[update[l] + l + 1] = sl[pos + l + 1];
      l++;
    }
  }
}

void iterate() {
  int elem = sl[1];
  while (sl[elem] != INFINITY) {
    // printf("%d ", sl[elem]);
    elem = sl[elem + 1];
  }
  // printf("\n");
}

void debug() {
  for (int i = 0; i < bufPtr; i++) {
    printf("%d ", sl[i]);
  }
  printf("\n");
}

void test() {
  printf("Inserez %d numere între 0 și %d\n", TRIAL_SIZE, MAX_VALUE - 1);
  for (int i = 0; i < TRIAL_SIZE; i++) {
    int x = rand() % MAX_VALUE;
    insert(x);
    check[x] = 1;
  }
  printf("Testez numerele între 0 și %d\n", MAX_VALUE - 1);
  int sum = 0;
  for (int i = 0; i < MAX_VALUE; i++) {
    assert(check[i] == search(i));
    sum += check[i];
  }
  printf("%d valori marcate\n", sum);
}

void markTime() {
  timeval tv;

  gettimeofday (&tv, NULL);
  t0 = 1000LL * tv.tv_sec + tv.tv_usec / 1000;
}

void reportTime(const char* msg) {
  timeval tv;

  gettimeofday (&tv, NULL);
  long long t = 1000LL * tv.tv_sec + tv.tv_usec / 1000;
  printf("%s: %lld ms\n", msg, t - t0);
}

int main(void) {
  ifstream in("hashuri.in");
    ofstream out("hashuri.out");

    ios_base::sync_with_stdio( false );

    srand( time( NULL ) );
    init();

    int N;

    in >> N;

    while ( N-- )
    {
        int tip, x;

        in >> tip >> x;

        switch(tip)
        {
            case 1: insert(x); break;
            case 2: erase(x); break;
            case 3: out << search(x) << "\n"; break;

            default: cerr << "Error\n";
        }
    }
}