ポテンシャル付きUnionFindです.
使用法
UnionFind uf(N); // 普通のUnionFind (ポテンシャル無し)
ld = uf.merge(a, b); // マージ.新しいリーダを返す
ld = uf.leader(a); // リーダ
ng = uf.num_groups(); // 全体のグループ数 ( == リーダの数)
sz = uf.group_size(a); // a が属するグループのサイズ
グループの要素のリストを得るためには,前処理として,GroupInfo を作る必要がある. これには,$O(N)$ かかる.
auto gi = uf.group_info();
for (int i : gi.group(a)) cout << i << endl; // a が属するグループの要素の列挙
ポテンシャル付きにするためには,テンプレートパラメタで,ポテンシャルの型を渡す. (デフォルトの型は,UFDummyAlg なるものになっている)
UnionFind<ll> uf1(N);
UnionFind<ftwo> uf2(N);
必要があれば,零元,和,単項マイナスを渡すこともできる:
UnionFind<ll> uf3(N, 0LL, plus<ll>(), negate<ll>());
ポテンシャル付きの時には,merge のときの第3引数に,ポテンシャルを渡さなければならない (省略不可)
ld = uf.merge(a, b, p); // b を基準にした a のポテンシャルが p である.p の型は T
ポテンシャルの値は,pot メソッドで取る.これの返り値型は,optional<T>
で,
ポテンシャルに矛盾がある時には,nullopt
を返す.
int ld = uf.merge(a, b, p0);
auto p = uf.pot(a);
if (p) {
cout << "The potential of " << a << " relative to " << ld << " is " << *p << endl;
assert(*uf.pot(a) - *uf.pot(b) == p0);
} else {
// ここに来るのは,merge の前から矛盾していたときや,
// a と b が同じグループに属していて,*uf.pot(a) - *uf.pot(b) が p0 と等しくなかったとき
cout << "Potential is undefined because of inconsistency." << endl;
}
ソース
キーワード: potential