結果
問題 | 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 nachiausing 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;}