library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub gyouzasushi/library

:heavy_check_mark: Weighted DSU
(datastructure/weighted_dsu.hpp)

概要

使い方

制約

計算量

Depends on

Verified with

Code

#pragma once
#include <algorithm>
#include <cassert>
#include <utility>
#include <vector>

#include "algebra/concept.hpp"

// potential p[v] of each vertex; diff(a, b) = op(inv(p[a]), p[b])
template <group G> struct weighted_dsu {
public:
    using S = typename G::S;
    weighted_dsu() : weighted_dsu(0) {
    }
    explicit weighted_dsu(int n) : _n(n), parent_or_size(n, -1), pot(n, G::e()) {
    }
    // make diff(a, b) == w; returns false if it contradicts the existing constraints
    bool merge(int a, int b, S w) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        int x = leader(a), y = leader(b);
        if (x == y) return diff(a, b) == w;
        // p[y] relative to x: op(inv(p[a]), op(p[y], p[b])) == w
        S py = G::op(G::op(pot[a], w), G::inv(pot[b]));
        if (-parent_or_size[x] < -parent_or_size[y]) {
            std::swap(x, y);
            py = G::inv(py);
        }
        parent_or_size[x] += parent_or_size[y];
        parent_or_size[y] = x;
        pot[y] = py;
        return true;
    }
    S diff(int a, int b) {
        assert(same(a, b));
        return G::op(G::inv(pot[a]), pot[b]);
    }
    bool same(int a, int b) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        return leader(a) == leader(b);
    }
    int leader(int a) {
        assert(0 <= a && a < _n);
        if (parent_or_size[a] < 0) return a;
        int p = parent_or_size[a];
        int r = leader(p);
        if (p != r) pot[a] = G::op(pot[p], pot[a]);
        return parent_or_size[a] = r;
    }
    int size(int a) {
        assert(0 <= a && a < _n);
        return -parent_or_size[leader(a)];
    }
    std::vector<std::vector<int>> groups() {
        std::vector<int> leader_buf(_n), group_size(_n);
        for (int i = 0; i < _n; i++) {
            leader_buf[i] = leader(i);
            group_size[leader_buf[i]]++;
        }
        std::vector<std::vector<int>> result(_n);
        for (int i = 0; i < _n; i++) result[i].reserve(group_size[i]);
        for (int i = 0; i < _n; i++) result[leader_buf[i]].push_back(i);
        result.erase(std::remove_if(result.begin(), result.end(),
                                    [&](const std::vector<int>& v) { return v.empty(); }),
                     result.end());
        return result;
    }

private:
    int _n;
    std::vector<int> parent_or_size;
    std::vector<S> pot;  // relative to parent
};
#line 2 "datastructure/weighted_dsu.hpp"
#include <algorithm>
#include <cassert>
#include <utility>
#include <vector>

#line 2 "algebra/concept.hpp"
#include <concepts>
template <class M>
concept semigroup = requires(typename M::S a, typename M::S b) {
    { M::op(a, b) } -> std::same_as<typename M::S>;
};
template <class M>
concept monoid = semigroup<M> && requires {
    { M::e() } -> std::same_as<typename M::S>;
};
template <class G>
concept group = monoid<G> && requires(typename G::S a) {
    { G::inv(a) } -> std::same_as<typename G::S>;
};
template <class A>
concept action = requires(typename A::F f, typename A::F g) {
    { A::composition(f, g) } -> std::same_as<typename A::F>;
    { A::id() } -> std::same_as<typename A::F>;
    { A::composition_commutative } -> std::convertible_to<bool>;
};
template <class A>
concept acted_monoid = monoid<A> && action<A> && requires(typename A::S x, typename A::F f) {
    { A::mapping(f, x) } -> std::same_as<typename A::S>;
};
template <class R>
concept semiring = requires(typename R::S a, typename R::S b) {
    { R::add(a, b) } -> std::same_as<typename R::S>;
    { R::zero() } -> std::same_as<typename R::S>;
    { R::mul(a, b) } -> std::same_as<typename R::S>;
    { R::one() } -> std::same_as<typename R::S>;
};
#line 8 "datastructure/weighted_dsu.hpp"

// potential p[v] of each vertex; diff(a, b) = op(inv(p[a]), p[b])
template <group G> struct weighted_dsu {
public:
    using S = typename G::S;
    weighted_dsu() : weighted_dsu(0) {
    }
    explicit weighted_dsu(int n) : _n(n), parent_or_size(n, -1), pot(n, G::e()) {
    }
    // make diff(a, b) == w; returns false if it contradicts the existing constraints
    bool merge(int a, int b, S w) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        int x = leader(a), y = leader(b);
        if (x == y) return diff(a, b) == w;
        // p[y] relative to x: op(inv(p[a]), op(p[y], p[b])) == w
        S py = G::op(G::op(pot[a], w), G::inv(pot[b]));
        if (-parent_or_size[x] < -parent_or_size[y]) {
            std::swap(x, y);
            py = G::inv(py);
        }
        parent_or_size[x] += parent_or_size[y];
        parent_or_size[y] = x;
        pot[y] = py;
        return true;
    }
    S diff(int a, int b) {
        assert(same(a, b));
        return G::op(G::inv(pot[a]), pot[b]);
    }
    bool same(int a, int b) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        return leader(a) == leader(b);
    }
    int leader(int a) {
        assert(0 <= a && a < _n);
        if (parent_or_size[a] < 0) return a;
        int p = parent_or_size[a];
        int r = leader(p);
        if (p != r) pot[a] = G::op(pot[p], pot[a]);
        return parent_or_size[a] = r;
    }
    int size(int a) {
        assert(0 <= a && a < _n);
        return -parent_or_size[leader(a)];
    }
    std::vector<std::vector<int>> groups() {
        std::vector<int> leader_buf(_n), group_size(_n);
        for (int i = 0; i < _n; i++) {
            leader_buf[i] = leader(i);
            group_size[leader_buf[i]]++;
        }
        std::vector<std::vector<int>> result(_n);
        for (int i = 0; i < _n; i++) result[i].reserve(group_size[i]);
        for (int i = 0; i < _n; i++) result[leader_buf[i]].push_back(i);
        result.erase(std::remove_if(result.begin(), result.end(),
                                    [&](const std::vector<int>& v) { return v.empty(); }),
                     result.end());
        return result;
    }

private:
    int _n;
    std::vector<int> parent_or_size;
    std::vector<S> pot;  // relative to parent
};
Back to top page