This documentation is automatically generated by online-judge-tools/verification-helper
#include "library/datastructure/union_find/union_find_lazy.hpp"
#ifndef SUISEN_UNION_FIND_COMPONENT_SUM
#define SUISEN_UNION_FIND_COMPONENT_SUM
#include "library/datastructure/union_find/linked_union_find.hpp"
namespace suisen {
/**
* @brief Union Find with lazy propagation
* @tparam T type of sum/value: commutative monoid
* @tparam F type of operator: (possibly non-commutative) group
* @tparam merge_sum (T& sum_parent, T sum_child) -> void
* @tparam neg (T x) -> -x
* @tparam mapping (F f, T& sum, int num) -> void
* @tparam composition (F f, F g) -> f * g
* @tparam id () -> identity
* @tparam inv (F f) -> f^(-1)
*/
template <typename T, void(*merge_sum)(T&, T), T(*neg)(T), typename F, void(*mapping)(F, T&, int), F(*composition)(F, F), F(*id)(), F(*inv)(F)>
struct UnionFindLazy : LinkedUnionFind {
UnionFindLazy() : UnionFindLazy(0) {}
explicit UnionFindLazy(int n, const T &init_value = T{}) : UnionFindLazy(std::vector<T>(n, init_value)) {}
explicit UnionFindLazy(const std::vector<T> &init_values) : LinkedUnionFind(init_values.size()), _val(init_values), _sum(init_values), _laz(_n, id()) {}
bool merge(int x, int y) {
x = root(x), y = root(y);
if (x == y) return false;
UnionFind::merge(x, y);
if (root(x) == y) std::swap(x, y);
F laz = composition(inv(_laz[x]), _laz[y]);
for (int v : connected_component(y)) {
mapping(laz, _val[v], 1);
}
merge_sum(_sum[x], std::move(_sum[y]));
std::swap(_link[x], _link[y]);
return true;
}
const T& get_component(int x) {
return _sum[root(x)];
}
T get_point(int x) {
T val = _val[x];
mapping(_laz[root(x)], val, 1);
return val;
}
void apply_component(int x, const F& f) {
x = root(x);
mapping(f, _sum[x], size(x));
_laz[x] = composition(f, _laz[x]);
}
void apply_point(int x, const F& f) {
_apply_point(x, [&f](T& old_value) { mapping(f, old_value, 1); });
}
void set_point(int x, const T &new_value) {
_apply_point(x, [&new_value](T& old_value) { old_value = new_value; });
}
void propagate(int x) {
x = root(x);
F laz = std::exchange(_laz[x], id());
for (int v : connected_component(x)) {
mapping(laz, _val[v], 1);
}
}
T& raw_value(int x) {
return _val[x];
}
const T& raw_value(int x) const {
return _val[x];
}
private:
std::vector<T> _val;
std::vector<T> _sum;
std::vector<F> _laz;
template <typename Mapping>
void _apply_point(int x, const Mapping& f) {
int r = root(x);
T v = get_point(x);
merge_sum(_sum[r], neg(v));
f(v);
merge_sum(_sum[r], v);
mapping(inv(_laz[r]), _val[x] = std::move(v), 1);
}
};
} // namespace suisen
#endif // SUISEN_UNION_FIND_COMPONENT_SUM
#line 1 "library/datastructure/union_find/union_find_lazy.hpp"
#line 1 "library/datastructure/union_find/linked_union_find.hpp"
#include <numeric>
#line 1 "library/datastructure/union_find/union_find.hpp"
#include <algorithm>
#include <vector>
namespace suisen {
struct UnionFind {
UnionFind() = default;
explicit UnionFind(int _n) : _n(_n), _dat(_n, -1) {}
// Get the root of `x`. equivalent to `operator[](x)`
int root(int x) {
static std::vector<int> buf;
while (_dat[x] >= 0) buf.push_back(x), x = _dat[x];
while (buf.size()) _dat[buf.back()] = x, buf.pop_back();
return x;
}
// Get the root of `x`. euivalent to `root(x)`
int operator[](int x) {
return root(x);
}
// Merge two vertices `x` and `y`.
bool merge(int x, int y) {
x = root(x), y = root(y);
if (x == y) return false;
if (_dat[x] > _dat[y]) std::swap(x, y);
_dat[x] += _dat[y], _dat[y] = x;
return true;
}
// Check if `x` and `y` belongs to the same connected component.
bool same(int x, int y) {
return root(x) == root(y);
}
// Get the size of connected componet to which `x` belongs.
int size(int x) {
return -_dat[root(x)];
}
// Get all of connected components.
std::vector<std::vector<int>> groups() {
std::vector<std::vector<int>> res(_n);
for (int i = 0; i < _n; ++i) res[root(i)].push_back(i);
res.erase(std::remove_if(res.begin(), res.end(), [](const auto& g) { return g.empty(); }), res.end());
return res;
}
protected:
int _n;
std::vector<int> _dat;
};
} // namespace suisen
#line 6 "library/datastructure/union_find/linked_union_find.hpp"
namespace suisen {
struct LinkedUnionFind : public UnionFind {
LinkedUnionFind() = default;
explicit LinkedUnionFind(int n) : UnionFind(n), _link(n) {
std::iota(_link.begin(), _link.end(), 0);
}
// Merge two vertices `x` and `y`.
bool merge(int x, int y) {
if (UnionFind::merge(x, y)) {
std::swap(_link[x], _link[y]);
return true;
}
return false;
}
// Get items connected to `x` (including `x`). Let the size of return value be `m`, time complexity is O(m).
std::vector<int> connected_component(int x) const {
std::vector<int> comp{ x };
for (int y = _link[x]; y != x; y = _link[y]) comp.push_back(y);
return comp;
}
protected:
std::vector<int> _link;
};
} // namespace suisen
#line 5 "library/datastructure/union_find/union_find_lazy.hpp"
namespace suisen {
/**
* @brief Union Find with lazy propagation
* @tparam T type of sum/value: commutative monoid
* @tparam F type of operator: (possibly non-commutative) group
* @tparam merge_sum (T& sum_parent, T sum_child) -> void
* @tparam neg (T x) -> -x
* @tparam mapping (F f, T& sum, int num) -> void
* @tparam composition (F f, F g) -> f * g
* @tparam id () -> identity
* @tparam inv (F f) -> f^(-1)
*/
template <typename T, void(*merge_sum)(T&, T), T(*neg)(T), typename F, void(*mapping)(F, T&, int), F(*composition)(F, F), F(*id)(), F(*inv)(F)>
struct UnionFindLazy : LinkedUnionFind {
UnionFindLazy() : UnionFindLazy(0) {}
explicit UnionFindLazy(int n, const T &init_value = T{}) : UnionFindLazy(std::vector<T>(n, init_value)) {}
explicit UnionFindLazy(const std::vector<T> &init_values) : LinkedUnionFind(init_values.size()), _val(init_values), _sum(init_values), _laz(_n, id()) {}
bool merge(int x, int y) {
x = root(x), y = root(y);
if (x == y) return false;
UnionFind::merge(x, y);
if (root(x) == y) std::swap(x, y);
F laz = composition(inv(_laz[x]), _laz[y]);
for (int v : connected_component(y)) {
mapping(laz, _val[v], 1);
}
merge_sum(_sum[x], std::move(_sum[y]));
std::swap(_link[x], _link[y]);
return true;
}
const T& get_component(int x) {
return _sum[root(x)];
}
T get_point(int x) {
T val = _val[x];
mapping(_laz[root(x)], val, 1);
return val;
}
void apply_component(int x, const F& f) {
x = root(x);
mapping(f, _sum[x], size(x));
_laz[x] = composition(f, _laz[x]);
}
void apply_point(int x, const F& f) {
_apply_point(x, [&f](T& old_value) { mapping(f, old_value, 1); });
}
void set_point(int x, const T &new_value) {
_apply_point(x, [&new_value](T& old_value) { old_value = new_value; });
}
void propagate(int x) {
x = root(x);
F laz = std::exchange(_laz[x], id());
for (int v : connected_component(x)) {
mapping(laz, _val[v], 1);
}
}
T& raw_value(int x) {
return _val[x];
}
const T& raw_value(int x) const {
return _val[x];
}
private:
std::vector<T> _val;
std::vector<T> _sum;
std::vector<F> _laz;
template <typename Mapping>
void _apply_point(int x, const Mapping& f) {
int r = root(x);
T v = get_point(x);
merge_sum(_sum[r], neg(v));
f(v);
merge_sum(_sum[r], v);
mapping(inv(_laz[r]), _val[x] = std::move(v), 1);
}
};
} // namespace suisen