22template <
class Idx = std::u
int32_t>
class UnionFind {
24 static_assert(std::is_unsigned_v<Idx>,
"UnionFind Idx must be an unsigned integer type");
31 explicit UnionFind(std::size_t n) : m_parent(n), m_rank(n, 0), m_size(n, 1), m_components(n) {
32 for (std::size_t i = 0; i < n; ++i) {
33 m_parent[i] =
static_cast<Idx
>(i);
48 assert(
static_cast<std::size_t
>(x) < m_parent.size() &&
"UnionFind::find index out of range");
50 while (m_parent[root] != root) {
51 root = m_parent[root];
54 while (m_parent[node] != root) {
55 const Idx next = m_parent[node];
56 m_parent[node] = root;
73 bool unite(Idx a, Idx b)
noexcept {
79 if (m_rank[ra] < m_rank[rb]) {
81 m_size[rb] += m_size[ra];
82 }
else if (m_rank[ra] > m_rank[rb]) {
84 m_size[ra] += m_size[rb];
87 m_size[ra] += m_size[rb];
119 [[nodiscard]] std::size_t
size() const noexcept {
return m_parent.size(); }
133 assert(
static_cast<std::size_t
>(root) < m_parent.size() &&
134 "UnionFind::componentSize index out of range");
139 std::vector<Idx> m_parent;
140 std::vector<std::uint8_t> m_rank;
141 std::vector<std::size_t> m_size;
142 std::size_t m_components;
Idx find(Idx x) noexcept
Root of the component containing x, with path compression applied.
std::size_t size() const noexcept
Total number of elements under management (fixed at construction).
bool unite(Idx a, Idx b) noexcept
Merge the components containing a and b.
std::size_t componentSize(Idx root) const noexcept
Population of the component whose root is root.
UnionFind(std::size_t n)
Construct n singleton components numbered [0, n).
bool sameComponent(Idx a, Idx b) noexcept
Whether a and b share a component.
std::size_t countComponents() const noexcept
Current number of distinct components.