#pragma once
template<typenameAbelGroup>classPotentialUnionFind{usingT=typenameAbelGroup::value_type;intn,num;std::vector<int>sz,parent;std::vector<T>potential;// parent[x] を基準とした時の x の値public:PotentialUnionFind()=default;PotentialUnionFind(intn):n(n),num(n),sz(n,1),parent(n,0),potential(n,AbelGroup::unit()){assert(AbelGroup::commute);std::iota(parent.begin(),parent.end(),0);}std::pair<int,T>from_root(intx){if(x==parent[x])return{x,AbelGroup::unit()};auto[r,add]=from_root(parent[x]);parent[x]=r;AbelGroup::Rchop(potential[x],add);return{r,potential[x]};}intleader(intx){returnfrom_root(x).first;}boolsame(intx,inty){assert(0<=xandx<nand0<=yandy<n);returnleader(x)==leader(y);}boolmerge(intx,inty,Td){// potential[y]-potential[x]=d にする// 矛盾する場合は変更はせず false を返すassert(0<=xandx<nand0<=yandy<n);auto[rx,dx]=from_root(x);auto[ry,dy]=from_root(y);AbelGroup::Rchop(d,dx);AbelGroup::Rchop(d,AbelGroup::inverse(dy));if(rx==ry)returnd==AbelGroup::unit();if(sz[rx]<sz[ry]){std::swap(rx,ry);d=AbelGroup::inverse(d);}sz[rx]+=sz[ry];parent[ry]=rx;potential[ry]=d;num--;returntrue;}std::optional<T>diff(intx,inty){// x を基準とするauto[rx,dx]=from_root(x);auto[ry,dy]=from_root(y);if(rx!=ry)returnstd::nullopt;returnAbelGroup::op(dy,AbelGroup::inverse(dx));}intsize(constintx){assert(0<=xandx<n);returnsz[leader(x)];}intcount()const{returnnum;}};
#line 2 "library/datastructure/unionfind/PotentialUnionFind.hpp"
template<typenameAbelGroup>classPotentialUnionFind{usingT=typenameAbelGroup::value_type;intn,num;std::vector<int>sz,parent;std::vector<T>potential;// parent[x] を基準とした時の x の値public:PotentialUnionFind()=default;PotentialUnionFind(intn):n(n),num(n),sz(n,1),parent(n,0),potential(n,AbelGroup::unit()){assert(AbelGroup::commute);std::iota(parent.begin(),parent.end(),0);}std::pair<int,T>from_root(intx){if(x==parent[x])return{x,AbelGroup::unit()};auto[r,add]=from_root(parent[x]);parent[x]=r;AbelGroup::Rchop(potential[x],add);return{r,potential[x]};}intleader(intx){returnfrom_root(x).first;}boolsame(intx,inty){assert(0<=xandx<nand0<=yandy<n);returnleader(x)==leader(y);}boolmerge(intx,inty,Td){// potential[y]-potential[x]=d にする// 矛盾する場合は変更はせず false を返すassert(0<=xandx<nand0<=yandy<n);auto[rx,dx]=from_root(x);auto[ry,dy]=from_root(y);AbelGroup::Rchop(d,dx);AbelGroup::Rchop(d,AbelGroup::inverse(dy));if(rx==ry)returnd==AbelGroup::unit();if(sz[rx]<sz[ry]){std::swap(rx,ry);d=AbelGroup::inverse(d);}sz[rx]+=sz[ry];parent[ry]=rx;potential[ry]=d;num--;returntrue;}std::optional<T>diff(intx,inty){// x を基準とするauto[rx,dx]=from_root(x);auto[ry,dy]=from_root(y);if(rx!=ry)returnstd::nullopt;returnAbelGroup::op(dy,AbelGroup::inverse(dx));}intsize(constintx){assert(0<=xandx<n);returnsz[leader(x)];}intcount()const{returnnum;}};