結果
問題 | No.2987 Colorful University of Tree |
ユーザー |
👑 ![]() |
提出日時 | 2024-11-21 06:00:15 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 636 ms / 5,000 ms |
コード長 | 8,331 bytes |
コンパイル時間 | 1,650 ms |
コンパイル使用メモリ | 104,112 KB |
最終ジャッジ日時 | 2025-02-25 05:40:19 |
ジャッジサーバーID (参考情報) |
judge2 / judge4 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 42 |
ソースコード
#include <iostream> #include <vector> #include <algorithm> #include <utility> #include <set> namespace nachia { struct RegularBipartiteGraph { int n; int k; std::vector<std::pair<int, int>> edges; }; RegularBipartiteGraph BipartiteRegularizeEdgeColorEquivalent( int n1, int n2, std::vector<std::pair<int,int>> edges ){ std::vector<int> ind1(n1); std::vector<int> ind2(n2); for(auto [u,v] : edges){ ind1[u]++; ind2[v]++; } int k = std::max( *std::max_element(ind1.begin(), ind1.end()), *std::max_element(ind2.begin(), ind2.end())); std::vector<int> map1(n1); std::vector<int> map2(n2); std::vector<int> indx1(std::max(n1, n2)); std::vector<int> indx2(std::max(n1, n2)); indx1[0] += ind1[0]; for(int i=1; i<n1; i++){ map1[i] = map1[i-1]; if(indx1[map1[i]] + ind1[i] > k) map1[i]++; indx1[map1[i]] += ind1[i]; } indx2[0] += ind2[0]; for(int i=1; i<n2; i++){ map2[i] = map2[i-1]; if(indx2[map2[i]] + ind2[i] > k) map2[i]++; indx2[map2[i]] += ind2[i]; } int n = std::max(map1.back() + 1, map2.back() + 1); RegularBipartiteGraph res = { n, k, std::vector<std::pair<int,int>>(n*k) }; for(int i=0; i<int(edges.size()); i++){ res.edges[i] = { map1[edges[i].first], map2[edges[i].second] }; } int s1 = 0; int s2 = 0; for(int i=int(edges.size()); i<n*k; i++){ while(indx1[s1] == k) s1++; while(indx2[s2] == k) s2++; res.edges[i] = { s1, s2 }; indx1[s1]++; indx2[s2]++; } return res; } std::vector<int> RegularBipartiteEdgeColor(const RegularBipartiteGraph& g){ int n = g.n * 2; std::vector<int> inci(n * g.k); int m = g.n * g.k; std::vector<int> xedge(m); { std::vector<int> head(n); for(int e=0; e<m; e++){ auto [u,v] = g.edges[e]; inci[g.k*(u*2+0) + head[u*2+0]++] = e; inci[g.k*(v*2+1) + head[v*2+1]++] = e; xedge[e] = (u*2+0) ^ (v*2+1); } } std::vector<int> flag_e(m); int nx_flag = 0; auto euler_splitting = [&]( std::vector<int> pl, std::vector<int> pr ) -> std::vector<int> { nx_flag++; for(int sp=0; sp<n; sp++){ int v = sp; while(true){ if(pl[v] == pr[v]){ if(sp == v) break; v ^= 1; continue; } int e = inci[pl[v]++]; int w = v; if(flag_e[e] != nx_flag){ flag_e[e] = nx_flag; w = v ^ xedge[e]; } if(w % 2 == 0) std::swap(inci[--pl[v]], inci[--pr[v]]); v = w; } } return pl; }; auto swap_group = [&]( const std::vector<int>& el, std::vector<int>& em, const std::vector<int>& er ) -> void { for(int i=0; i<n; i++){ int len = std::min(em[i] - el[i], er[i] - em[i]); std::swap_ranges( inci.begin() + el[i], inci.begin() + (el[i] + len), inci.begin() + (er[i] - len)); em[i] = er[i] + el[i] - em[i]; } }; auto take_matching = [&]( int s, int d ) -> void { std::vector<int> pl(n); std::vector<int> pr(n); for(int i=0; i<n; i++) pl[i] = i * g.k + s; for(int i=0; i<n; i++) pr[i] = i * g.k + s + d; std::vector<int> pm = pr; int md = 1; while(md < n/2*d) md *= 2; int alpha = md / d; while(alpha % 2 == 0){ alpha /= 2; md /= 2; } for(int w=1; w<md; w*=2){ if(alpha & w){ auto plm = euler_splitting(pl, pm); int count_edges = 0; for(int i=0; i<n; i+=2) count_edges += pm[i] + pl[i] - plm[i] * 2; if(count_edges < 0) swap_group(pl, plm, pm); std::swap(pm, plm); } else { auto pmr = euler_splitting(pm, pr); int count_edges = 0; for(int i=0; i<n; i+=2) count_edges += pr[i] + pm[i] - pmr[i] * 2; if(count_edges < 0) swap_group(pm, pmr, pr); std::swap(pm, pmr); } } }; auto part_color = [&]( auto& rec, int s, int d ) -> void { if(d <= 1) return; int d2 = d; if(d2 % 2 == 1){ if(s+d2 < g.k) d2++; else{ take_matching(s, d2); d2--; } } std::vector<int> pl(n); std::vector<int> pr(n); for(int i=0; i<n; i++) pl[i] = i * g.k + s; for(int i=0; i<n; i++) pr[i] = i * g.k + s + d2; euler_splitting(std::move(pl), std::move(pr)); rec(rec, s+d2/2, d2/2); rec(rec, s, d2/2); }; part_color(part_color, 0, g.k); std::vector<int> ans(m); for(int i=0; i<n; i+=2) for(int j=0; j<g.k; j++) ans[inci[i*g.k+j]] = j; return ans; } std::vector<int> BipartiteEdgeColor( int n1, int n2, std::vector<std::pair<int,int>> edges ){ int m = edges.size(); auto regularized = BipartiteRegularizeEdgeColorEquivalent(n1, n2, std::move(edges)); auto ans = RegularBipartiteEdgeColor(regularized); ans.resize(m); return ans; } } // namespace nachia using namespace std; #define rep(i,n) for(int i=0; i<int(n); i++) pair<int, vector<int>> bin_packing(vector<int> weight){ int N = weight.size(); int N_original = N; int odd_count = 0; for(int a : weight) if(a % 2 == 1) odd_count += 1; int sum = N * 2 - 2; int Q = *max_element(weight.begin(), weight.end());; while(true){ int req = sum; if(Q % 2 == 1) req += max(0, Q - odd_count); if(req <= (long long)Q * Q) break; Q += 1; } int P = (sum + Q - 1) / Q; if(P < Q) P += 1; while(sum < P*Q){ weight.push_back(1); sum += 1; N += 1; odd_count += 1; } set<pair<int,int>> even_group, odd_group; rep(i,N) (weight[i] % 2 ? odd_group : even_group).insert({ -weight[i], i }); even_group.insert({ 1, -100 }); odd_group.insert({ 1, -100 }); vector<int> ans(N, -1); auto set_ans = [&](int i, int c){ if(i < 0) exit(1); (weight[i] % 2 ? odd_group : even_group).erase({ -weight[i], i }); ans[i] = c; if(weight[i] % 2 == 1) odd_count -= 1; }; auto extract_max_at = [&](set<pair<int,int>>& src, int x){ pair<int,int> res = *src.lower_bound({ -x, -1 }); res.first *= -1; return res; }; auto extract_max = [&](int x){ return max(extract_max_at(even_group, x), extract_max_at(odd_group, x)); }; rep(i,P){ int to_pack = Q; if(Q % 2 == 1){ if(odd_count == P - i){ auto [w,v] = extract_max_at(odd_group, to_pack); set_ans(v, i); to_pack -= w; } while(to_pack > 0){ auto [w,v] = (odd_count == P-i-1) ? extract_max_at(even_group, to_pack) : extract_max(to_pack); set_ans(v, i); to_pack -= w; } } else { while(to_pack > 0){ auto [w,v] = extract_max(to_pack); set_ans(v, i); to_pack -= w; } } } ans.resize(N_original); return {Q,ans}; } void testcase(){ int N; cin >> N; vector<vector<int>> edges(N); rep(i,N){ int c; cin >> c; rep(j,c){ int e; cin >> e; e--; edges[i].push_back(e); } } vector<int> deg(N); rep(i,N) deg[i] = edges[i].size(); auto [Q, vcolor] = bin_packing(deg); vector<pair<int,int>> bedge; rep(i,N) rep(j,edges[i].size()){ bedge.push_back({ vcolor[i], edges[i][j] }); edges[i][j] = int(bedge.size()) - 1; } auto bcolor = nachia::BipartiteEdgeColor(Q, N-1, bedge); cout << Q << '\n'; rep(i,N){ cout << (vcolor[i] + 1); for(auto e : edges[i]) cout << ' ' << (bcolor[e] + 1); cout << '\n'; } } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); int T; cin >> T; rep(ti,T) testcase(); return 0; }