AtCoder が提供しているABC(AtCoder Beginner Contest)328 のF問題をC++で解いてみました。ABC328は、2023年11月11日21:00に実施されました。
AtCoder の紹介はこちらに、プログラミングの方針はこちらに記事があります。
F問題 Good Set Query(Difficulty : 1477)
問題はリンク先をご覧ください。
重み付きUnionFindを使って解くことができました。AtCoder Problems による Difficulty は 1477 でした。
解答案
前日に、重み付きUnionFindの紹介をしました(記事)。このライブラリをそのまま使うだけで、この問題を解くことができます。
C++ プログラム例(ABC328F)
クラス Weighted_UnionFind は、整備したコードをそのまま使いました(6ー77行目)。
(ai, bi, di) を加えると良い集合にならない条件をまとめます。
- ai と bi が連結していることが前提となります。逆に ai と bi が連結していなければ連結して良い集合となります。
- 上記を満たして、bi と ai の距離が di ではない。
良い集合となる添え字を出力します。以下が、C++プログラムとなります。
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
class Weighted_UnionFind {
private:
int n;
std::vector<int> par;
std::vector<ll> diff_weight;
public:
Weighted_UnionFind(int _n) {
n = _n;
par.resize(n, -1);
diff_weight.resize(n, 0);
}
int leader(int x) {
if (par[x] < 0) {
return x;
} else {
int r = leader(par[x]);
diff_weight[x] += diff_weight[par[x]];
return par[x] = r;
}
}
ll weight(int x) {
leader(x);
return diff_weight[x];
}
ll diff(int x, int y) {
return weight(y) - weight(x);
}
void merge(int x, int y, ll w) {
w += weight(x);
w -= weight(y);
x = leader(x);
y = leader(y);
if (x != y) {
if (-par[x] < -par[y]) {
std::swap(x, y);
w = -w;
}
par[x] += par[y];
par[y] = x;
diff_weight[y] = w;
}
}
bool same(int x, int y) {
return leader(x) == leader(y);
}
int size(int x) {
return -par[leader(x)];
}
std::vector<std::vector<int>> groups() {
std::vector<std::vector<int>> member(n);
for (int i = 0; i < n; ++i) {
member[leader(i)].push_back(i);
}
std::vector<std::vector<int>> result;
for (int i = 0; i < n; ++i) {
if (!member[i].empty()) {
result.push_back(member[i]);
}
}
return result;
}
};
int main()
{
int n, q;
cin >> n >> q;
Weighted_UnionFind uf(n + 1);
vector<int> result;
for (int i = 0; i < q; ++i) {
int a, b;
ll d;
cin >> a >> b >> d;
if (uf.same(a, b)) {
if (uf.diff(b, a) != d) {
continue;
}
} else {
uf.merge(b, a, d);
}
result.push_back(i + 1);
}
for (int i = 0; i < result.size(); ++i) {
cout << result[i] << " \n"[i == result.size() - 1];
}
return 0;
}
AC(Accepted=正しいプログラム)と判定されました。
Python の重み付きUnionFindについて
Python は、重み付きUnionFind を標準ライブラリとしては用意していません。このブログの Python プログラムは、なるべく言語標準のライブラリで実装したいと考えています。このような事情で、この記事では、Python に移植したプログラムの紹介を省略します。
最後に
コンテストでは解くことができませんでした。公式解説を参考にして、先にライブラリを整備しました。知っていれば解ける問題だと感じました。焦らず自分が使える道具を増やしていきます。
引き続き ABC の問題を紹介していきます。