cafelier のSRM参加記録です。コンテスト中に考えてたことを執拗に全部書き残すとどうなるだろうかという試み本番中にこういうコードが書きたかったなあ、という後で書いた反省コードを書き残す試み
スパムが来たのでしばらくコメント欄をはてなユーザ限定にしています、すみません、
今回はUnionFind祭りだった。
struct UnionFind { vector<int> uf, sz; int nc; UnionFind(int N): uf(N), sz(N,1), nc(N) { for(int i=0; i<N; ++i) uf[i] = i; } int size() { return nc; } int Find(int a) { return uf[a]==a ? a : uf[a]=Find(uf[a]); } bool Union(int a, int b) { a = Find(a); b = Find(b); if( a != b ) { if( sz[a] >= sz[b] ) swap(a, b); uf[a] = b; sz[b] += sz[a]; --nc; } return (a!=b); } }; typedef int vert; typedef tuple<vert,vert> edge; int solve(const vector<edge>& edges, int N, int K) { int removed = 0; // とりあえず白白辺を全部結ぶ UnionFind uf(N); for(edge e : edges) { vert a = get<0>(e); vert b = get<1>(e); if( a >= K && b >= K ) uf.Union(a,b); } // 他の辺はサイクル作らないように結ぶ for(edge e : edges) { vert a = get<0>(e); vert b = get<1>(e); if( a < K || b < K ) if( !uf.Union(a,b) ) ++removed; } return removed; } int main() { int T; cin >> T; for(int C=1; C<=T; ++C) { int N, M, K; cin >> N >> M >> K; vector<edge> edges; for(int i=0; i<M; ++i) { int a,b; cin >> a >> b; edges.emplace_back(a, b); } cout << "Case #" << C << ": " << solve(edges, N, K) << endl; } }
FHC | |
typedef tuple<int, int> merger; template<typename T> struct UnionFind { vector<int> uf, sz; vector<T> info; int nc; UnionFind(int N, const T& ini): uf(N), sz(N,1), nc(N), info(N, ini) { for(int i=0; i<N; ++i) uf[i] = i; } int size() { return nc; } int Find(int a) { return uf[a]==a ? a : uf[a]=Find(uf[a]); } T& Info(int a) { return info[Find(a)]; } template<typename F> bool Union(int a, int b, F info_merger) { a = Find(a); b = Find(b); if( a != b ) { if( sz[a] >= sz[b] ) swap(a, b); uf[a] = b; sz[b] += sz[a]; info_merger(info[b], info[a]); --nc; } return (a!=b); } }; int solve(const vector<merger>& ms, int N, int D) { typedef vector<int> HD; static const int INF = 0x3fffffff; UnionFind<HD> uf(N, HD({INF,0})); for(auto m : ms) { uf.Union(get<0>(m), get<1>(m), [&](HD& a, HD b){ int aMinD = INF; int bMinD = INF; HD c(max(a.size(),b.size())+1, INF); for(int h=1; h<c.size(); ++h) { int c1 = aMinD>=INF || h>=b.size() ? INF : b[h]+1; int c2 = bMinD>=INF || h>=a.size() ? INF : a[h]+1; int c3 = aMinD>=INF || h-1>=b.size() || b[h-1]>=INF ? INF : min(aMinD, b[h-1])+1; int c4 = bMinD>=INF || h-1>=a.size() || a[h-1]>=INF ? INF : min(bMinD, a[h-1])+1; c[h] = min({c1, c2, c3, c4, INF}); if(c[h]>D) c[h] = INF; if(h<a.size()) aMinD = min(aMinD, a[h]); if(h<b.size()) bMinD = min(bMinD, b[h]); } a = c; }); } HD& hd = uf.Info(0); for(int h=0; h<hd.size(); ++h) if( hd[h] <= D ) return h; return -1; } int main() { int T; cin >> T; for(int C=1; C<=T; ++C) { int N, D; cin >> N >> D; vector<merger> ms(N-1); for(auto& m : ms) { cin >> get<0>(m) >> get<1>(m); -- get<0>(m); -- get<1>(m); } cout << "Case #" << C << ": " << solve(ms, N, D) << endl; } }
presented by cafelier/k.inaba under