結果

問題 No.2987 Colorful University of Tree
ユーザー 👑 Nachia
提出日時 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
権限があれば一括ダウンロードができます

ソースコード

diff #
プレゼンテーションモードにする

#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;
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
0