重みつきUnionFindは、UnionFind木を理解していればあっという間に実装できます。
と、言うのも、UnionFind木で親をたどっていく操作の途中で、重みも一緒に計算すればいいだけだからです。
ホントにそれだけです。添字がめんどくさいぐらい。
#include <bits/stdc++.h> using namespace std; class UnionFind { public: //配列のでかさは調整 vector<vector<long long int>>par; //int par[1000009]; int siz[1000009]; // N 頂点の Union-Find を作成 void init(int N) { for (int i = 1; i <= N+10; i++) par.push_back({-1,0}); // 最初は親が無い for (int i = 1; i <= N; i++) siz[i] = 1; // 最初はグループの頂点数が 1 } // 頂点 x の根を返す関数 int root(int x) { while (true) { if (par[x][0] == -1) break; // 1 個先(親)がなければ、ここが根 x = par[x][0]; // 1 個先(親)に進む } return x; } // 要素 u と v を統合する関数(v+w==u) void unite(int u, int v,int w) { int RootU = root(u); int RootV = root(v); if (RootU == RootV) return; // u と v が同グループのときは処理を行わない if (siz[RootU] < siz[RootV]) { par[RootU][1] = w+kyori_ne(v)+kyori_ne(u)*-1; par[RootU][0] = RootV; siz[RootV] = siz[RootU] + siz[RootV]; } else { par[RootV][1] = w*-1+kyori_ne(u)+kyori_ne(v)*-1; par[RootV][0] = RootU; siz[RootU] = siz[RootU] + siz[RootV]; } } // 要素 u と v が同一のグループかどうかを返す関数 bool same(int u, int v) { if (root(u) == root(v)) return true; return false; } //その頂点の根との差を出力 long long int kyori_ne(int x){ long long int count=0; while(true){ if(par[x][0]==-1)break; count+=par[x][1]; x=par[x][0]; } return count; } //v-uを出力 long long int kyori(int u,int v){ //もし同一グループでなかったら-1を返す if(same(u,v)==false)return -1; return kyori_ne(u)-kyori_ne(v); } //要素nが属しているグループのデカさ int dekasa(int n){ return siz[root(n)]; } void checker(){ for (int i=0;i<par.size();i++)cout << par[i][0] << " " << par[i][1] << endl; } };