Cod sursa(job #3325568)

Utilizator Razvan23Razvan Mosanu Razvan23 Data 25 noiembrie 2025 19:19:32
Problema Hashuri Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.35 kb
#include <bits/stdc++.h>
using namespace std;

ifstream fin("hashuri.in");
ofstream fout("hashuri.out");

// --- CONSTANTE PENTRU 1.000.000 OPERATII ---
// Dimensiunea tabelei de hash (Buckets).
// 666013 este un numar prim clasic. Poti folosi si 1000003 pentru coliziuni mai putine.
const int N_HASH = 666013;

// Numarul maxim de elemente care vor fi inserate vreodata.
// Fiindca N <= 1.000.000, avem nevoie de un buffer de 1M.
const int MAX_NODES = 1000005;

// --- MEMORIE STATICA (GLOBAL) ---
// head[h] = indexul primului nod din bucket-ul h
int head[N_HASH];

// val[i] = valoarea stocata in nodul i
// urm[i] = indexul urmatorului nod (simuleaza pointerul 'next')
int val[MAX_NODES];
int urm[MAX_NODES];

// Cursor pentru a sti unde punem urmatorul element inserat
int pos = 1;

// Functie de hash puternica pentru a evita coliziunile pe teste "anti-hash"
struct Hasher {
    inline int operator()(int x) {
        // Operatii pe biti pentru viteza maxima
        // Amestecam bitii pentru a evita coliziuni pe numere consecutive
        x ^= x >> 16;
        x *= 0x85ebca6b;
        x ^= x >> 13;
        x *= 0xc2b2ae35;
        x ^= x >> 16;

        // Modulo pozitiv
        int res = x % N_HASH;
        if (res < 0) res += N_HASH;
        return res;
    }
} getHash;

class Hash {
public:
    // Inserare O(1)
    void Insert(int x) {
        int h = getHash(x);

        // Verificam daca exista deja (pentru unicitate)
        // Parcurgem lista bucket-ului h
        for (int p = head[h]; p != 0; p = urm[p]) {
            if (val[p] == x) return; // Exista deja
        }

        // Adaugam nod nou la inceputul listei (cel mai rapid)
        val[pos] = x;       // Scriem valoarea la pozitia curenta a cursorului
        urm[pos] = head[h]; // Noul nod pointeaza catre vechiul cap de lista
        head[h] = pos;      // Capul listei devine noul nod

        pos++; // Avansam cursorul
    }

    // Stergere O(1) amortizat
    void Delete(int x) {
        int h = getHash(x);

        // Trebuie sa tinem minte nodul anterior pentru a reface legatura
        int p = head[h];
        int ant = 0;

        while (p != 0) {
            if (val[p] == x) {
                if (ant == 0) {
                    // Cazul 1: Stergem primul element din lista
                    head[h] = urm[p];
                } else {
                    // Cazul 2: Stergem un element din interior
                    urm[ant] = urm[p]; // Sarim peste 'p'
                }
                // Nota: Nu recuperam memoria (pos nu scade).
                // La 1M operatii avem memorie suficienta (aprox 12MB ocupati din 64/128MB).
                return;
            }
            ant = p;
            p = urm[p];
        }
    }

    // Cautare O(1) amortizat
    bool Find(int x) {
        int h = getHash(x);
        for (int p = head[h]; p != 0; p = urm[p]) {
            if (val[p] == x) return true;
        }
        return false;
    }
};

int main() {
    // Optimizare I/O obligatorie pentru 1.000.000 linii
    ios_base::sync_with_stdio(0);
    fin.tie(0);
    fout.tie(0);

    Hash H;
    int n, op, x;

    fin >> n;
    while(n--) {
        fin >> op >> x;
        if (op == 1) H.Insert(x);
        else if (op == 2) H.Delete(x);
        else fout << H.Find(x) << "\n";
    }

    return 0;
}