結果

問題 No.2987 Colorful University of Tree
ユーザー 👑 hos.lyrichos.lyric
提出日時 2024-12-13 08:16:46
言語 C++14
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 802 ms / 5,000 ms
コード長 9,510 bytes
コンパイル時間 2,339 ms
コンパイル使用メモリ 141,172 KB
実行使用メモリ 65,080 KB
最終ジャッジ日時 2024-12-13 08:17:14
合計ジャッジ時間 26,305 ms
ジャッジサーバーID
(参考情報)
judge5 / judge4
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
6,820 KB
testcase_01 AC 2 ms
6,820 KB
testcase_02 AC 151 ms
6,816 KB
testcase_03 AC 185 ms
6,820 KB
testcase_04 AC 186 ms
6,820 KB
testcase_05 AC 528 ms
34,128 KB
testcase_06 AC 134 ms
11,816 KB
testcase_07 AC 93 ms
10,376 KB
testcase_08 AC 452 ms
31,136 KB
testcase_09 AC 140 ms
15,376 KB
testcase_10 AC 675 ms
47,468 KB
testcase_11 AC 534 ms
41,172 KB
testcase_12 AC 800 ms
63,964 KB
testcase_13 AC 548 ms
41,232 KB
testcase_14 AC 547 ms
41,024 KB
testcase_15 AC 688 ms
41,668 KB
testcase_16 AC 656 ms
50,736 KB
testcase_17 AC 682 ms
54,400 KB
testcase_18 AC 582 ms
41,088 KB
testcase_19 AC 549 ms
41,164 KB
testcase_20 AC 571 ms
41,348 KB
testcase_21 AC 536 ms
41,200 KB
testcase_22 AC 546 ms
41,136 KB
testcase_23 AC 802 ms
65,080 KB
testcase_24 AC 226 ms
7,936 KB
testcase_25 AC 223 ms
7,936 KB
testcase_26 AC 226 ms
7,932 KB
testcase_27 AC 235 ms
7,936 KB
testcase_28 AC 229 ms
7,824 KB
testcase_29 AC 14 ms
6,820 KB
testcase_30 AC 78 ms
6,820 KB
testcase_31 AC 77 ms
6,820 KB
testcase_32 AC 188 ms
6,820 KB
testcase_33 AC 232 ms
12,264 KB
testcase_34 AC 283 ms
16,648 KB
testcase_35 AC 299 ms
28,384 KB
testcase_36 AC 576 ms
38,268 KB
testcase_37 AC 77 ms
10,676 KB
testcase_38 AC 320 ms
28,436 KB
testcase_39 AC 73 ms
9,572 KB
testcase_40 AC 404 ms
31,196 KB
99_evil_hack_000.txt AC 2 ms
6,820 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

// no proof, please hack me

#include <cassert>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <functional>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

using namespace std;

using Int = long long;

template <class T1, class T2> ostream &operator<<(ostream &os, const pair<T1, T2> &a) { return os << "(" << a.first << ", " << a.second << ")"; };
template <class T> ostream &operator<<(ostream &os, const vector<T> &as) { const int sz = as.size(); os << "["; for (int i = 0; i < sz; ++i) { if (i >= 256) { os << ", ..."; break; } if (i > 0) { os << ", "; } os << as[i]; } return os << "]"; }
template <class T> void pv(T a, T b) { for (T i = a; i != b; ++i) cerr << *i << " "; cerr << endl; }
template <class T> bool chmin(T &t, const T &f) { if (t > f) { t = f; return true; } return false; }
template <class T> bool chmax(T &t, const T &f) { if (t < f) { t = f; return true; } return false; }
#define COLOR(s) ("\x1b[" s "m")


// !!!Modifies ns and edges!!!
// n: modified regular bipartite graph
// d := max degree = edge chromatic number
// iss[c]: edges of color c \in [0, d)
// colors[i]: color of edge i
struct BipartiteEdgeColoring {
  int ns[2];
  vector<pair<int, int>> edges;
  int n;
  int d;
  vector<int> colors;
  vector<vector<int>> iss;
  BipartiteEdgeColoring() {}
  BipartiteEdgeColoring(int n0, int n1) : ns{n0, n1}, edges() {}
  void ae(int u, int v) {
    assert(0 <= u); assert(u < ns[0]);
    assert(0 <= v); assert(v < ns[1]);
    edges.emplace_back(u, v);
  }
  void run() {
    const int m = edges.size();
    vector<int> deg[2];
    for (int s = 0; s < 2; ++s) deg[s].assign(ns[s], 0);
    for (const auto &edge : edges) {
      ++deg[0][edge.first];
      ++deg[1][edge.second];
    }
    d = 0;
    for (int s = 0; s < 2; ++s) for (int u = 0; u < ns[s]; ++u) if (d < deg[s][u]) d = deg[s][u];
    // Merge vertices of small degree.
    for (int s = 0; s < 2; ++s) {
      priority_queue<pair<int, int>, vector<pair<int, int>>, std::greater<pair<int, int>>> que;
      par.resize(ns[s]);
      for (int u = 0; u < ns[s]; ++u) que.emplace(deg[s][u], par[u] = u);
      for (; ; ) {
        if (!que.size()) break;
        const auto p0 = que.top(); que.pop();
        if (!que.size()) break;
        const auto p1 = que.top(); que.pop();
        if (p0.first + p1.first > d) break;
        par[p0.second] = p1.second;
        que.emplace(p0.first + p1.first, p1.second);
      }
      int nn = 0;
      vector<int> ids(ns[s], -1);
      for (int u = 0; u < ns[s]; ++u) if (par[u] == u) ids[u] = nn++;
      ns[s] = nn;
      if (s == 0) {
        for (auto &edge : edges) edge.first = ids[root(edge.first)];
      } else {
        for (auto &edge : edges) edge.second = ids[root(edge.second)];
      }
    }
    // Add edges to make the graph d-regular.
    n = max(ns[0], ns[1]);
    for (int s = 0; s < 2; ++s) deg[s].assign(n, 0);
    for (const auto &edge : edges) {
      ++deg[0][edge.first];
      ++deg[1][edge.second];
    }
    for (int u = 0, v = 0; ; ) {
      for (; u < n && deg[0][u] >= d; ++u) {}
      for (; v < n && deg[1][v] >= d; ++v) {}
      if (u == n && v == n) break;
      edges.emplace_back(u, v);
      ++deg[0][u];
      ++deg[1][v];
    }
    iss.clear();
    vector<int> is(n * d);
    for (int i = 0; i < n * d; ++i) is[i] = i;
    rec(is);
    // Remove added edges.
    colors.assign(m, -1);
    for (int k = 0; k < d; ++k) {
      iss[k].erase(std::lower_bound(iss[k].begin(), iss[k].end(), m), iss[k].end());
      for (const int i : iss[k]) colors[i] = k;
    }
  }
  vector<int> par;
  int root(int u) {
    return (par[u] == u) ? u : (par[u] = root(par[u]));
  }
  // is: k-regular
  void rec(vector<int> is) {
    if (!is.size()) return;
    const int k = is.size() / n;
    if (k == 1) {
      std::sort(is.begin(), is.end());
      iss.push_back(is);
    } else if (k % 2 != 0) {
      if (iss.size()) {
        is.insert(is.end(), iss.back().begin(), iss.back().end());
        iss.pop_back();
        rec(is);
      } else {
        // Add (2^e - k) bad matchings to find a perfect matching.
        const int e = (31 - __builtin_clz(k)) + 1;
        vector<int> ma(n);
        for (int u = 0; u < n; ++u) ma[u] = ~u;
        for (; ; ) {
          auto js = is;
          for (const int j : ma) for (int l = 0; l < (1 << e) - k; ++l) js.push_back(j);
          for (int f = e; --f >= 0; ) {
            const auto jss = euler(js);
            int numBads[2] = {};
            for (int s = 0; s < 2; ++s) for (const int i : jss[s]) if (i < 0) ++numBads[s];
            js = jss[(numBads[0] <= numBads[1]) ? 0 : 1];
          }
          ma.swap(js);
          bool good = true;
          for (const int j : ma) if (j < 0) {
            good = false;
            break;
          }
          if (good) break;
        }
        std::sort(ma.begin(), ma.end());
        iss.push_back(ma);
        std::sort(is.begin(), is.end());
        vector<int> iis;
        auto it = ma.begin();
        for (const int i : is) {
          for (; it != ma.end() && *it < i; ++it) {}
          if (!(it != ma.end() && *it == i)) iis.push_back(i);
        }
        rec(iis);
      }
    } else {
      const auto jss = euler(is);
      for (int s = 0; s < 2; ++s) rec(jss[s]);
    }
  }
  // Take Eulerian circuit and take edges alternately.
  vector<vector<int>> euler(const vector<int> &is) {
    const int k = is.size() / n;
    vector<int> pt(n + n);
    for (int u = 0; u < n + n; ++u) pt[u] = u * k;
    vector<pair<int, int>> xvs((n + n) * k);
    for (int x = 0; x < n * k; ++x) {
      const int i = is[x];
      int u, v;
      if (i >= 0) {
        u = edges[i].first;
        v = n + edges[i].second;
      } else {
        u = ~i;
        v = n + ~i;
      }
      xvs[pt[u]++] = std::make_pair(x, v);
      xvs[pt[v]++] = std::make_pair(x, u);
    }
    vector<int> used(n * k, 0);
    int y = 0;
    vector<vector<int>> jss(2, vector<int>(n * (k / 2)));
    vector<int> stack;
    for (int u0 = 0; u0 < n; ++u0) {
      for (stack.push_back(u0); stack.size(); ) {
        const int u = stack.back();
        if (pt[u] > u * k) {
          --pt[u];
          const int x = xvs[pt[u]].first;
          const int v = xvs[pt[u]].second;
          if (!used[x]) {
            used[x] = 1;
            jss[y & 1][y >> 1] = is[x];
            ++y;
            stack.push_back(v);
          }
        } else {
          stack.pop_back();
        }
      }
    }
    return jss;
  }
};

////////////////////////////////////////////////////////////////////////////////


vector<int> greedy(const vector<int> &deg, int m) {
  const int n = deg.size();
  priority_queue<pair<int, int>> que;
  for (int i = 0; i < m; ++i) que.emplace(m, i);
  vector<pair<int, int>> dus(n);
  for (int u = 0; u < n; ++u) dus[u] = make_pair(deg[u], u);
  sort(dus.begin(), dus.end(), greater<pair<int, int>>{});
  vector<int> ret(n, 0);
  for (const auto &du : dus) {
    const int c = que.top().first;
    const int i = que.top().second;
    que.pop();
    if (c < du.first) return {};
    que.emplace(c - du.first, i);
    ret[du.second] = i;
  }
  return ret;
}

int getM(const vector<int> &deg) {
  const int n = deg.size();
  Int m = 0;
  for (; !(2 * n - 2 <= m * m); ++m) {}
  for (int u = 0; u < n; ++u) chmax<Int>(m, deg[u]);
  // girigiri, but too few odd
  Int sum = 0;
  for (int u = 0; u < n; ++u) sum += deg[u] / 2;
  for (; !(sum <= m * (m/2)); ++m) {}
  return m;
}

namespace exper {
int N;
vector<int> deg;
Int counter;
void test() {
// cerr<<"[test] "<<deg<<endl;
  ++counter;
  const int m = getM(deg);
  const auto res = greedy(deg, m);
  if (!res.size()) {
    cerr << "FAIL " << deg << " " << m << endl;
    assert(false);
  }
}
void dfs(int u, int e, int d) {
  if (e > (N - u) * d) return;
  if (u == N) {
    test();
  } else {
    for (chmin(d, e); d >= 0; --d) {
      deg[u] = 1 + d;
      dfs(u + 1, e - d, d);
    }
  }
}
void run() {
  for (N = 2; ; ++N) {
    deg.resize(N);
    counter = 0;
    dfs(0, N - 2, N - 2);
    cerr << "PASSED N = " << N << ": counter = " << counter << endl;
  }
}
}  // exper
// DONE N = 83: counter = 18004327


int N;
vector<int> C;
vector<vector<int>> E;

int main() {
  // exper::run();
  
  for (int numCases; ~scanf("%d", &numCases); ) { for (int caseId = 1; caseId <= numCases; ++caseId) {
    scanf("%d", &N);
    C.resize(N);
    E.resize(N);
    for (int u = 0; u < N; ++u) {
      scanf("%d", &C[u]);
      E[u].resize(C[u]);
      for (int c = 0; c < C[u]; ++c) {
        scanf("%d", &E[u][c]);
        --E[u][c];
      }
    }
    
    const int M = getM(C);
    const auto res = greedy(C, M);
    
    /*
      side 0: endpoints of edge
      side 1: edge from same vertex color
    */
    BipartiteEdgeColoring bec(N - 1, M);
    for (int u = 0; u < N; ++u) {
      for (int c = 0; c < C[u]; ++c) {
        bec.ae(E[u][c], res[u]);
      }
    }
    bec.run();
    assert(bec.d <= M);
    
    printf("%d\n", M);
    int id = 0;
    for (int u = 0; u < N; ++u) {
      printf("%d", res[u] + 1);
      for (int c = 0; c < C[u]; ++c) {
        printf(" %d", bec.colors[id++] + 1);
      }
      puts("");
    }
  }
#ifndef LOCAL
  break;
#endif
  }
  return 0;
}
0