Skip to content

Commit

Permalink
Update Weighted UnionFind
Browse files Browse the repository at this point in the history
  • Loading branch information
ruthen71 committed May 4, 2024
1 parent 5a51e07 commit 603c093
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 4 deletions.
23 changes: 21 additions & 2 deletions data_structure/weighted_unionfind.hpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
#pragma once

template <class T> struct WeightedUnionFind {
int n;
std::vector<int> parents;
std::vector<T> diff_weight;

WeightedUnionFind() {}
WeightedUnionFind(int n) : parents(n, -1), diff_weight(n) {}
WeightedUnionFind(int n) : n(n), parents(n, -1), diff_weight(n, T(0)) {}

int leader(int x) {
if (parents[x] < 0) {
Expand Down Expand Up @@ -42,5 +43,23 @@ template <class T> struct WeightedUnionFind {

int size(int x) { return -parents[leader(x)]; }

void init(int n) { parents.assign(n, -1), diff_weight.assign(n, 0); } // reset
// 連結成分ごとに (頂点番号 v, diff(leader(v), v)) の配列を返す
std::vector<std::vector<std::pair<int, T>>> 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<std::pair<int, T>>> 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]].emplace_back(i, weight(i));
}
result.erase(std::remove_if(result.begin(), result.end(), [&](const std::vector<std::pair<int, T>>& v) { return v.empty(); }), result.end());
return result;
}

void init(int n) { parents.assign(n, -1), diff_weight.assign(n, T(0)); } // reset
};
5 changes: 3 additions & 2 deletions docs/data_structure/weighted_unionfind.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ documentation_of: //data_structure/weighted_unionfind.hpp
- 各頂点に対し、「親の頂点番号」「親への辺の重み」「根なら部分木のサイズ」の 3 つの情報が持てれば良い
- 「親の頂点番号」「根なら部分木のサイズ」はどの頂点もどちらかあれば OK なので `parents` でまとめている
- 「親への辺の重み」は `diff_weight` が持つ(頂点が根ならアーベル群の単位元を入れる)
- `merge()` の説明
- `merge()`
- 各頂点 `x` に対し、`weight(x)``leader(x)` からの差分となっている
- もともと `w``weight(y) - weight(x)` となっており、`w += weight(x)` によって `w``weight(y) - weight(leader(x))` となり、`w -= weight(y)` によって `w``weight(leader(y)) - weight(leader(x))` となり、最後に、`leader(x)``leader(y)` を Union by Size している
- `leader(x)` の重みを 0 として、相対的に表現しているため、`diff_weight[y] = w` でOK

- `groups()`
- UnionFind では各連結成分ごとに頂点番号のリストを返すが、Weighted UnionFind では頂点番号とその頂点番号の根からの重みの組のリストを返す

0 comments on commit 603c093

Please sign in to comment.