#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 // Nimber struct Nimber { using ull = unsigned long long; ull v; const static std::array, 256> small_table; const static std::array, 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 friend IStream &operator>>(IStream &is, Nimber &x) { ull v; return is >> v, x = Nimber(v), is; } template 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, 256> Nimber::small_table = []() { std::array, 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, 8>, 8> Nimber::precalc = []() { std::array, 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 #include #include // CUT begin // Weighted UnionFind template struct WeightedUnionFind { std::vector par, sz; std::vector 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 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 friend OStream &operator<<(OStream &os, const F2vec &x) { return os << x.val; } }; #line 5 "unionfind/test/weighted_unionfind_F2.yuki1420.test.cpp" #include using namespace std; int main() { cin.tie(nullptr), ios::sync_with_stdio(false); int N, M; cin >> N >> M; WeightedUnionFind 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'; }