Pagini recente » Cod sursa (job #3351689) | Cod sursa (job #1006397) | Cod sursa (job #3310461) | Cod sursa (job #3340069) | Cod sursa (job #3325567)
#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 = (1<<16)-1;
// 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;
}