shogo-library

競技プログラミング用の C++ ライブラリ

View the Project on GitHub shogo314/shogo-library

:heavy_check_mark: test/unittest/mex-update.test.cpp

Depends on

Code

#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A"

// MexUpdate を愚直な実装とランダムに比較する
// 問題の入力は使わず、すべて一致したら Hello World を出力する

#include <iostream>
#include <random>
#include <set>
#include <vector>

#include "../../src/data_structures/mex-update.hpp"

// v に含まれない最小の非負整数
template <typename T>
T naive_mex(const std::vector<T>& v) {
    std::set<T> s(v.begin(), v.end());
    T x = 0;
    while (s.count(x)) x++;
    return x;
}

template <typename T>
bool run(std::mt19937& rng) {
    for (int rep = 0; rep < 2000; rep++) {
        int n = rng() % 8 + 1;
        // 範囲外の値 (負の値や n より大きい値) も混ぜる
        auto random_value = [&]() -> T { return static_cast<T>(static_cast<int>(rng() % (n + 6)) - 3); };
        std::vector<T> v;
        MexUpdate<T> mu;
        if (rep % 2 == 0) {
            // MexUpdate(n): 値はどれも mex に影響しない値で初期化される
            mu = MexUpdate<T>(n);
            v.assign(n, -1);
            if (mu.prod() != 0) return false;
        } else {
            v.resize(n);
            for (auto& x : v) x = random_value();
            mu = MexUpdate<T>(v);
        }
        if (mu.prod() != naive_mex(v)) return false;
        for (int t = 0; t < 20; t++) {
            int k = rng() % n;
            T x = random_value();
            mu.set(k, x);
            v[k] = x;
            if (mu.prod() != naive_mex(v)) return false;
        }
    }
    return true;
}

int main() {
    std::mt19937 rng(314);
    bool ok = run<int>(rng) && run<long long>(rng);
    // 0..n-1 がすべて揃うと mex は n
    MexUpdate<int> full(std::vector<int>{2, 0, 1});
    ok = ok && full.prod() == 3;
    full.set(1, 3);
    ok = ok && full.prod() == 0;
    if (ok) std::cout << "Hello World" << std::endl;
    else std::cerr << "failed" << std::endl;
}
#line 1 "test/unittest/mex-update.test.cpp"
#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A"

// MexUpdate を愚直な実装とランダムに比較する
// 問題の入力は使わず、すべて一致したら Hello World を出力する

#include <iostream>
#include <random>
#include <set>
#include <vector>

#line 2 "src/data_structures/mex-update.hpp"

/**
 * @file mex-update.hpp
 * @brief 1点更新・全体の mex 取得
 */

#include <cassert>
#include <limits>
#include <map>
#line 13 "src/data_structures/mex-update.hpp"

template <typename T>
struct MexUpdate {
    using value_type = T;

   private:
    inline constexpr static value_type e = std::numeric_limits<value_type>::max();

    int n;
    std::vector<value_type> v;
    std::set<int> s;
    std::map<int, size_t> m;

   public:
    MexUpdate() = default;
    MexUpdate(int n) : n(n), v(n, e) {
        assert(n > 0);
        assert(n + 1 < e);
        std::set<int>::iterator hint = s.end();
        for (int i = n; i >= 0; --i) {
            hint = s.emplace_hint(hint, i);
        }
    }
    MexUpdate(const std::vector<value_type>& init) : n(init.size()), v(init) {
        assert(n > 0);
        assert(n + 1 < e);
        std::set<int>::iterator hint = s.end();
        for (int i = n; i >= 0; --i) {
            hint = s.emplace_hint(hint, i);
        }
        for (const auto& i : init) {
            if (0 <= i and i <= n) {
                m[i]++;
                s.erase(i);
            }
        }
    }
    void set(int k, const value_type& x) {
        assert(0 <= k and k < n);
        if (0 <= v[k] and v[k] <= n) {
            int v_k = v[k];
            auto itr = m.find(v_k);
            if (itr->second > 1) {
                itr->second--;
            } else {
                m.erase(itr);
                s.insert(v_k);
            }
        }
        if (0 <= x and x <= n) {
            int xx = x;
            auto itr = m.find(xx);
            if (itr == m.end()) {
                m[xx]++;
                s.erase(xx);
            } else {
                itr->second++;
            }
        }
        v[k] = x;
    }
    value_type prod() const {
        return *s.begin();
    }
};
#line 12 "test/unittest/mex-update.test.cpp"

// v に含まれない最小の非負整数
template <typename T>
T naive_mex(const std::vector<T>& v) {
    std::set<T> s(v.begin(), v.end());
    T x = 0;
    while (s.count(x)) x++;
    return x;
}

template <typename T>
bool run(std::mt19937& rng) {
    for (int rep = 0; rep < 2000; rep++) {
        int n = rng() % 8 + 1;
        // 範囲外の値 (負の値や n より大きい値) も混ぜる
        auto random_value = [&]() -> T { return static_cast<T>(static_cast<int>(rng() % (n + 6)) - 3); };
        std::vector<T> v;
        MexUpdate<T> mu;
        if (rep % 2 == 0) {
            // MexUpdate(n): 値はどれも mex に影響しない値で初期化される
            mu = MexUpdate<T>(n);
            v.assign(n, -1);
            if (mu.prod() != 0) return false;
        } else {
            v.resize(n);
            for (auto& x : v) x = random_value();
            mu = MexUpdate<T>(v);
        }
        if (mu.prod() != naive_mex(v)) return false;
        for (int t = 0; t < 20; t++) {
            int k = rng() % n;
            T x = random_value();
            mu.set(k, x);
            v[k] = x;
            if (mu.prod() != naive_mex(v)) return false;
        }
    }
    return true;
}

int main() {
    std::mt19937 rng(314);
    bool ok = run<int>(rng) && run<long long>(rng);
    // 0..n-1 がすべて揃うと mex は n
    MexUpdate<int> full(std::vector<int>{2, 0, 1});
    ok = ok && full.prod() == 3;
    full.set(1, 3);
    ok = ok && full.prod() == 0;
    if (ok) std::cout << "Hello World" << std::endl;
    else std::cerr << "failed" << std::endl;
}
Back to top page