Cod sursa(job #3325565)

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

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

// CONSTANTE
const int N_HASH = 666013; // Dimensiunea tabelei (Numar prim)
const int MAX_OPS = 200005; // Numarul maxim de inserari (din enuntul problemei)

// MEMORIE STATICA (Alocata in segmentul de date, nu pe heap)
// head[h] = indexul primului element din bucket-ul h
int head[N_HASH];

// Acestea simuleaza nodurile: valoare si pointerul 'next'
int val[MAX_OPS];
int urm[MAX_OPS];
int pos = 1; // Cursorul pentru alocare (incepem de la 1, 0 inseamna NULL)

// Functia de Hash (Pastram SplitMix64 pentru siguranta)
struct CustomHash {
    long long splitmix64(long long x) const {
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }
    int operator()(int x) const {
        // Hardcodat random pentru viteza maxima (evitam chrono la fiecare apel)
        return (splitmix64(x + 0x9e3779b9) % N_HASH + N_HASH) % N_HASH;
    }
} hasher;

class FastHash {
public:
    void Insert(int x) {
        int h = hasher(x);

        // Verificam daca exista deja (optional, depinde de problema)
        for (int p = head[h]; p != 0; p = urm[p]) {
            if (val[p] == x) return;
        }

        // Inseram la INCEPUTUL listei (O(1) pur)
        // 1. Punem valoarea in pozitia curenta libera
        val[pos] = x;
        // 2. Legam noul nod de vechiul 'head' al bucket-ului
        urm[pos] = head[h];
        // 3. Noul nod devine 'head'
        head[h] = pos;

        // 4. Avansam cursorul pentru urmatoarea inserare
        pos++;
    }

    void Delete(int x) {
        int h = hasher(x);

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

        while (p != 0) {
            if (val[p] == x) {
                if (ant == 0) {
                    // Stergem primul element: Head-ul devine urmatorul
                    head[h] = urm[p];
                } else {
                    // Stergem element din interior: Anteriorul sare peste 'p'
                    urm[ant] = urm[p];
                }
                // Nu "eliberam" memoria la pos, o lasam "pierduta".
                // In concursuri memoria e ieftina, timpul e scump.
                return;
            }
            ant = p;
            p = urm[p];
        }
    }

    bool Find(int x) {
        int h = hasher(x);
        // Parcurgem lista folosind indici in loc de pointeri
        for (int p = head[h]; p != 0; p = urm[p]) {
            if (val[p] == x) return true;
        }
        return false;
    }
};

int main() {
    // Optimizari I/O standard
    ios_base::sync_with_stdio(0);
    fin.tie(0);
    fout.tie(0);

    // Nu mai trebuie instantiata clasa daca e totul static/global,
    // dar folosim un obiect wrapper pentru curatenie.
    FastHash A;

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

    return 0;
}