結果

問題 No.1420 国勢調査 (Easy)
ユーザー 👑 hitonanodehitonanode
提出日時 2021-10-27 23:35:23
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 83 ms / 2,000 ms
コード長 5,125 bytes
コンパイル時間 1,562 ms
コンパイル使用メモリ 99,468 KB
実行使用メモリ 5,376 KB
最終ジャッジ日時 2024-04-16 12:47:27
合計ジャッジ時間 6,172 ms
ジャッジサーバーID
(参考情報)
judge4 / judge1
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 35 ms
5,248 KB
testcase_01 AC 35 ms
5,376 KB
testcase_02 AC 66 ms
5,376 KB
testcase_03 AC 66 ms
5,376 KB
testcase_04 AC 66 ms
5,376 KB
testcase_05 AC 67 ms
5,376 KB
testcase_06 AC 67 ms
5,376 KB
testcase_07 AC 44 ms
5,376 KB
testcase_08 AC 57 ms
5,376 KB
testcase_09 AC 46 ms
5,376 KB
testcase_10 AC 57 ms
5,376 KB
testcase_11 AC 40 ms
5,376 KB
testcase_12 AC 39 ms
5,376 KB
testcase_13 AC 46 ms
5,376 KB
testcase_14 AC 40 ms
5,376 KB
testcase_15 AC 47 ms
5,376 KB
testcase_16 AC 46 ms
5,376 KB
testcase_17 AC 46 ms
5,376 KB
testcase_18 AC 47 ms
5,376 KB
testcase_19 AC 46 ms
5,376 KB
testcase_20 AC 45 ms
5,376 KB
testcase_21 AC 46 ms
5,376 KB
testcase_22 AC 81 ms
5,376 KB
testcase_23 AC 81 ms
5,376 KB
testcase_24 AC 81 ms
5,376 KB
testcase_25 AC 83 ms
5,376 KB
testcase_26 AC 80 ms
5,376 KB
testcase_27 AC 54 ms
5,376 KB
testcase_28 AC 54 ms
5,376 KB
testcase_29 AC 46 ms
5,376 KB
testcase_30 AC 54 ms
5,376 KB
testcase_31 AC 53 ms
5,376 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#line 1 "unionfind/test/weighted_unionfind_F2.yuki1420.test.cpp"
#define PROBLEM "https://yukicoder.me/problems/no/1420"
#define ERROR 1 // Check only whether the answer is -1 or not
#line 2 "number/nimber.hpp"
#include <array>

// Nimber
struct Nimber {
    using ull = unsigned long long;
    ull v;
    const static std::array<std::array<unsigned, 256>, 256> small_table;
    const static std::array<std::array<std::array<ull, 256>, 8>, 8> precalc;

    explicit operator bool() const { return v != 0; }
    Nimber(ull val = 0) : v(val) {}
    Nimber operator+(const Nimber &x) const { return Nimber(v ^ x.v); }
    Nimber operator-(const Nimber &x) const { return Nimber(v ^ x.v); }
    Nimber operator-() const { return *this; }
    Nimber &operator+=(const Nimber &x) { return *this = *this + x; }
    Nimber &operator-=(const Nimber &x) { return *this = *this + x; }
    template <class IStream> friend IStream &operator>>(IStream &is, Nimber &x) {
        ull v;
        return is >> v, x = Nimber(v), is;
    }
    template <class OStream> friend OStream &operator<<(OStream &os, const Nimber &x) {
        return os << x.v;
    }
    bool operator==(const Nimber &x) const { return v == x.v; }
    bool operator!=(const Nimber &x) const { return v != x.v; }
    bool operator<(const Nimber &x) const { return v < x.v; }

    static ull _rec(ull x, ull y) {
        if (x == 0 or y == 0) return 0;
        if (x < y) x ^= y, y ^= x, x ^= y; // Make x >= y
        if (y == 1) return x;
        for (int shift = 64 / 2;; shift >>= 1) {
            ull mask = (1ULL << shift) - 1;
            if (y >> shift) {
                ull v00 = _rec(x & mask, y & mask);
                ull v01 = _rec(x & mask, y >> shift);
                ull v10 = _rec(x >> shift, y & mask);
                ull v11 = _rec(x >> shift, y >> shift);
                return v00 ^ ((v01 ^ v10 ^ v11) << shift) ^ _rec(v11, 1ULL << (shift - 1));
            } else if (x >> shift) {
                return (_rec(x >> shift, y) << shift) ^ _rec(x & mask, y);
            }
        }
    }
    Nimber operator*(const Nimber &x) const {
        ull ret = 0;
        for (int d = 0; d < 8; ++d) {
            for (int e = 0; e < 8; ++e) {
                ret ^= precalc[d][e][small_table[(v >> (d * 8)) & 255][(x.v >> (e * 8)) & 255]];
            }
        }
        return Nimber(ret);
    }
    Nimber &operator*=(const Nimber &x) { return *this = *this * x; }
};

const std::array<std::array<unsigned, 256>, 256> Nimber::small_table = []() {
    std::array<std::array<unsigned, 256>, 256> ret;
    for (int i = 0; i < 256; ++i) {
        for (int j = 0; j < 256; ++j) ret[i][j] = _rec(i, j);
    }
    return ret;
}();
const std::array<std::array<std::array<unsigned long long, 256>, 8>, 8> Nimber::precalc = []() {
    std::array<std::array<std::array<unsigned long long, 256>, 8>, 8> ret;
    for (int d = 0; d < 8; ++d) {
        for (int e = 0; e < 8; ++e) {
            ull p = _rec(1ULL << (8 * d), 1ULL << (8 * e));
            for (int i = 0; i < 256; ++i) ret[d][e][i] = _rec(p, i);
        }
    }
    return ret;
}();
#line 2 "unionfind/weighted_unionfind.hpp"
#include <numeric>
#include <utility>
#include <vector>

// CUT begin
// Weighted UnionFind
template <class S> struct WeightedUnionFind {
    std::vector<int> par, sz;
    std::vector<S> pot;
    WeightedUnionFind(int N = 0) : par(N), sz(N, 1), pot(N) { std::iota(par.begin(), par.end(), 0); }
    int find(int x) {
        if (par[x] != x) {
            int r = find(par[x]);
            pot[x] = pot[x] + pot[par[x]], par[x] = r;
        }
        return par[x];
    }
    bool unite(int s, int t, S rel_diff) {
        // Relate s and t by t = s + rel_diff
        // Return false iff contradiction happens.
        rel_diff = rel_diff + weight(s) + (-weight(t));
        if ((s = find(s)) == (t = find(t))) return rel_diff == 0;
        if (sz[s] < sz[t]) std::swap(s, t), rel_diff = -rel_diff;
        par[t] = s, sz[s] += sz[t], pot[t] = rel_diff;
        return true;
    }
    S weight(int x) { return find(x), pot[x]; }
    S diff(int s, int t) { return weight(t) + (-weight(s)); }
    int count(int x) { return sz[find(x)]; }
    bool same(int s, int t) { return find(s) == find(t); }
};

template <typename Int> struct F2vec {
    Int val;
    F2vec(Int x = 0) : val(x) {}
    F2vec operator+(const F2vec &y) const { return F2vec(y.val ^ val); }
    F2vec operator-() const { return *this; }
    bool operator==(const F2vec &x) const { return val == x.val; }
    template <class OStream> friend OStream &operator<<(OStream &os, const F2vec &x) { return os << x.val; }
};
#line 5 "unionfind/test/weighted_unionfind_F2.yuki1420.test.cpp"
#include <iostream>
using namespace std;

int main() {
    cin.tie(nullptr), ios::sync_with_stdio(false);
    int N, M;
    cin >> N >> M;

    WeightedUnionFind<Nimber> uf(N);
    while (M--) {
        int a, b, y;
        cin >> a >> b >> y;
        a--, b--;
        if (!uf.unite(a, b, y)) {
            cout << "-1\n";
            return 0;
        }
    }
    for (int i = 0; i < N; i++) cout << uf.weight(i) << '\n';
}
0