Cod sursa(job #2872081)

Utilizator StanCatalinStanCatalin StanCatalin Data 16 martie 2022 12:04:20
Problema Hashuri Scor 70
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 6.77 kb
//#include <iostream>
//#include <cstdlib>
//#include <fstream>
//
//using namespace std;
//
//ifstream in("hashuri.in");
//ofstream out("hashuri.out");
//
//const int p = 1500041;
//const int m = 668611;
//
//long long int a1, b1;
//
//int calculate_hash_function_1(long long int x) {
//    return ((long long)(a1 * x + b1) % p) % m;
//}
//
//long long int a2, b2;
//
//int calculate_hash_function_2(long long int x) {
//    return ((long long )(a2 * x + b2) % p) % m;
//}
//
//long long int T1[m], T2[m];
//
//bool Search(long long int x) {
//    return (T1[calculate_hash_function_1(x)] == x || T2[calculate_hash_function_2(x)] == x);
//}
//
//void Insert(long long int x) {
//    long long int y, z;
//    int h1 = calculate_hash_function_1(x);
//    if (T1[h1] == 0 || T1[h1] == x) {
//        T1[h1] = x;
//        return;
//    } else {
//        y = T1[h1];
//        T1[h1] = x;
//    }
//    int h2 = calculate_hash_function_2(y);
//    if (T2[h2] == 0 || T2[h2] == y) {
//        T2[h2] = y;
//        return;
//    } else {
//        z = T2[h2];
//        T2[h2] = y;
//    }
//    Insert(z);
//}
//
//void Delete(long long int x) {
//    int h1 = calculate_hash_function_1(x);
//    int h2 = calculate_hash_function_2(x);
//    if (T1[h1] == x) {
//        T1[h1] = 0;
//    }
//    if (T2[h1] == x) {
//        T2[h2] = 0;
//    }
//}
//
//int main() {
//
//    srand(time(nullptr));
//    a1 = rand()%p;
//    b1 = rand()%p;
//    a2 = rand()%p;
//    b2 = rand()%p;
//
//    long long int n, op, x;
//    in >> n;
//    while (n--) {
//        in >> op >> x;
//        if (op == 1) {
//            Insert(x);
//        } else if (op == 2) {
//            Delete(x);
//        } else {
//            out << Search(x) << "\n";
//        }
//    }
//
//
//    return 0;
//}

#include <iostream>
#include <cmath>
#include <fstream>
#include <vector>

using namespace std;

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

class MyHashMap {
public:
    /** Initialize your data structure here. */
    MyHashMap()  {
    }

    /** value will always be non-negative. */
    void put(int key, int value) {
        //if incdeces hash1[key] or hash2[key] contains needed key, then we can just update value
        //else we need to push any key out

        auto h1 = hash1(key), h2 = hash2(key);
        if (buffer_[h1].first == key)
            buffer_[h1].second = value;
        else if (buffer_[h2].first == key)
            buffer_[h2].second = value;
        else
            push(key, value);

    }

    /** Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key */
    int get(int key) {
        //Main feature of cuckoo hashing -- just check two positions

        auto h1 = hash1(key), h2 = hash2(key);

        if (buffer_[h1].first == key)
            return buffer_[h1].second;

        if (buffer_[h2].first == key)
            return buffer_[h2].second;

        return -1;
    }

    /** Removes the mapping of the specified value key if this map contains a mapping for the key */
    void remove(int key) {
        auto h1 = hash1(key), h2 = hash2(key);

        if (buffer_[h1].first == key){
            buffer_[h1] = EMPTY;
            --count_;
        }
        else if (buffer_[h2].first == key){
            buffer_[h2] = EMPTY;
            --count_;
        }
    }
private:
    size_t hash(int hash_param, int key) const {
        //arbitrary family of hash functions. hash_param determines the instance of hash function
        return std::hash<int>()(key) / hash_param % (buffer_.size() / 2);
    }

    size_t hash1(int key) const { return hash(hash1_, key); }
    size_t hash2(int key) const { return hash(hash2_, key) + buffer_.size() / 2; }

    void push(int key, int value){
        ++count_;

        //to control load factor
        if (count_ >= buffer_.size() / 4)
            resize();

        //switch for changing hash functions.
        //if we used i2 = hash1(k1) previously and pushed out some other key k2: i2 = hash1(k2),
        //we have to use other hash  i2' = hash2(k2) to find a new place for k2.
        bool switcher = true;
        for (size_t i = 0; i < limit_; ++i) {
            auto h1 = hash1(key), h2 = hash2(key);
            if (buffer_[h1] == EMPTY){
                buffer_[h1] = {key, value};
                break;
            }

            if (buffer_[h2] == EMPTY){
                buffer_[h2] = {key, value};
                break;
            }

            auto h = switcher ? h1 : h2;
            std::swap(key, buffer_[h].first);
            std::swap(value, buffer_[h].second);

            switcher = !switcher;


            //If we gonna exceed the limit, we can rehash current map with new hash functions.
            //Note, we can try to do it without resizing.
            //After that we should insert current pushed out key to the new place.
            if (i + 1 == limit_){
                rehash();
                i = static_cast<size_t>(-1);
            }
        }
    }

    void rehash(){
        //Defining new hash functions is hard so I used simple ones.
        //First hash function I left static.
        hash1_ = 1;
        hash2_ = rand() % limit_ + 1;

        //Durty hack. We gonna rehash elements. We can do it inplace with `put` function.
        //But we have to change limit_ variable to the number of elements during rehashing.
        auto real_limit = limit_;
        limit_ = count_;
        for (size_t i = 0; i < buffer_.size(); ++i){
            if (buffer_[i] != EMPTY && hash1(buffer_[i].first) != i && hash2(buffer_[i].first) != i){
                auto p = buffer_[i];
                buffer_[i] = EMPTY;
                put(p.first, p.second);
            }
        }
        limit_ = real_limit;
    }

    void resize(){
        //limit parameter can be tuned. It seems to be ok if limit is a*log2(N).
        buffer_.resize(buffer_.size() * 2, EMPTY);
        limit_ = 50 * static_cast<int>(std::log2(buffer_.size()));
        rehash();
    }

    //number of elements
    size_t count_ = 0;

    //current max number of cuckoo pushing
    int limit_ = 2;

    //parameters of hash functions
    int hash1_ = 1, hash2_ = 2;

    //buffer with parameters {key, value}
    const std::pair<int, int> EMPTY = {-1, -1};
    std::vector<std::pair<int,int> > buffer_ = std::vector<std::pair<int,int> >(2, EMPTY);
};

/**
 * Your MyHashMap object will be instantiated and called as such:
 * MyHashMap* obj = new MyHashMap();
 * obj->put(key,value);
 * int param_2 = obj->get(key);
 * obj->remove(key);
 */

int main() {
    MyHashMap* obj = new MyHashMap();
    long long int n, op, x;
    in >> n;
    while (n--) {
        in >> op >> x;
        if (op == 1) {
            obj->put(x, 0);
        } else if (op == 2) {
            obj->remove(x);
        } else {
            out << obj->get(x) + 1 << "\n";
        }
    }


    return 0;
}