G - Hidden Weights Editorial by blueberry1001

重み付きUnionFindを使用した解法

重み付きUnionFindを用いた解法を紹介します。
参考:けんちょんさんの記事
重み付きUnionFindは、

  • 通常のUnionFindと同じく、無向グラフの連結関係を管理する
  • 連結である2頂点の重みの差を求める

ことができます。この問題では、連結成分に含まれる頂点の中から親を一人決め、親の重みを0とし、他の頂点は親との重みの差で重みを決めることで解を構成することができるため、重み付きUnionFindで解くことができます。

また、重み付きUnionFindをテーマにした問題集がAtCoder NoviStepsに用意されています。重み付きUnionFindへの理解を深める良い練習になるでしょう。

実装例(C++)

#include<bits/stdc++.h>
using namespace std;

template<class Abel> struct WeightedUnionFind {
     vector<int> par;
     vector<int> rank;
     vector<Abel> diff_weight;
 
     WeightedUnionFind(int n = 1, Abel SUM_UNITY = 0) {
         init(n, SUM_UNITY);
     }
 
     void init(int n = 1, Abel SUM_UNITY = 0) {
         par.resize(n); rank.resize(n); diff_weight.resize(n);
         for (int i = 0; i < n; ++i) par[i] = i, rank[i] = 0, diff_weight[i] = SUM_UNITY;
     }
 
     int root(int x) {
         if (par[x] == x) {
             return x;
         }
         else {
             int r = root(par[x]);
             diff_weight[x] += diff_weight[par[x]];
             return par[x] = r;
         }
     }
 
     Abel weight(int x) {
         root(x);
         return diff_weight[x];
     }
 
     bool issame(int x, int y) {
         return root(x) == root(y);
     }
 
     bool merge(int x, int y, Abel w) {
         w += weight(x); w -= weight(y);
         x = root(x); y = root(y);
         if (x == y) return false;
         if (rank[x] < rank[y]) swap(x, y), w = -w;
         if (rank[x] == rank[y]) ++rank[x];
         par[y] = x;
         diff_weight[y] = w;
         return true;
     }
 
     Abel diff(int x, int y) {
         return weight(y) - weight(x);
     }
 };

int main(){
	int n,m;cin >> n >> m;
	WeightedUnionFind<long long>uf(n);
	for(int i = 0;i<m;i++){
		int u,v;
		long long w;
		cin >> u >> v >> w;
		u--,v--;
		uf.merge(u,v,w);
	}
	for(int i = 0;i<n;i++){
		cout << uf.weight(i) << " ";
	}
	cout << endl;
	return 0;
}

提出コード(C++) https://atcoder.jp/contests/abc373/submissions/58292961

posted:
last update: