1
0

AtCoder-qupc2018_h.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. struct DSU {
  4. vector<int> parent;
  5. explicit DSU(int n = 0) : parent(n) { iota(parent.begin(), parent.end(), 0); }
  6. int find(int x) {
  7. while (parent[x] != x) {
  8. parent[x] = parent[parent[x]];
  9. x = parent[x];
  10. }
  11. return x;
  12. }
  13. void unite(int a, int b) {
  14. a = find(a);
  15. b = find(b);
  16. if (a != b) parent[b] = a;
  17. }
  18. };
  19. int main() {
  20. ios::sync_with_stdio(false);
  21. cin.tie(nullptr);
  22. int n;
  23. cin >> n;
  24. vector<int> radius(n);
  25. for (int &x : radius) {
  26. cin >> x;
  27. x = (x - 1) / 2;
  28. }
  29. int levels = 1;
  30. while ((1 << levels) <= n) ++levels;
  31. vector<int> count(levels), length(levels);
  32. vector<DSU> dsu;
  33. dsu.reserve(levels);
  34. for (int k = 0; k < levels; ++k) {
  35. length[k] = 1 << k;
  36. count[k] = n - length[k] + 1;
  37. dsu.emplace_back(2 * count[k]);
  38. }
  39. for (int i = 0; i < n; ++i) dsu[0].unite(i, count[0] + i);
  40. auto node = [&](int k, int start, bool reversed) {
  41. return start + (reversed ? count[k] : 0);
  42. };
  43. for (int center = 0; center < n; ++center) {
  44. int remaining = radius[center];
  45. int offset = 0;
  46. while (remaining > 0) {
  47. int k = 31 - __builtin_clz(remaining);
  48. int block = 1 << k;
  49. int left_start = center - radius[center] + offset;
  50. int right_start = center + radius[center] - offset - block + 1;
  51. dsu[k].unite(node(k, left_start, false), node(k, right_start, true));
  52. offset += block;
  53. remaining -= block;
  54. }
  55. }
  56. for (int k = levels - 1; k >= 1; --k) {
  57. int half = 1 << (k - 1);
  58. auto children = [&](int id) {
  59. bool reversed = id >= count[k];
  60. int start = id - (reversed ? count[k] : 0);
  61. if (!reversed) {
  62. return pair<int, int>{node(k - 1, start, false),
  63. node(k - 1, start + half, false)};
  64. }
  65. return pair<int, int>{node(k - 1, start + half, true),
  66. node(k - 1, start, true)};
  67. };
  68. for (int id = 0; id < 2 * count[k]; ++id) {
  69. int root = dsu[k].find(id);
  70. if (root == id) continue;
  71. auto [a1, a2] = children(id);
  72. auto [b1, b2] = children(root);
  73. dsu[k - 1].unite(a1, b1);
  74. dsu[k - 1].unite(a2, b2);
  75. }
  76. }
  77. vector<vector<int>> unequal(n);
  78. for (int center = 0; center < n; ++center) {
  79. int left = center - radius[center] - 1;
  80. int right = center + radius[center] + 1;
  81. if (left >= 0 && right < n) {
  82. int a = dsu[0].find(left);
  83. int b = dsu[0].find(right);
  84. unequal[a].push_back(b);
  85. unequal[b].push_back(a);
  86. }
  87. }
  88. vector<vector<int>> members(n);
  89. for (int i = 0; i < n; ++i) members[dsu[0].find(i)].push_back(i);
  90. vector<int> roots;
  91. for (int i = 0; i < n; ++i) if (!members[i].empty()) roots.push_back(i);
  92. sort(roots.begin(), roots.end(), [&](int a, int b) {
  93. return members[a][0] < members[b][0];
  94. });
  95. vector<int> color(n, -1);
  96. for (int root : roots) {
  97. bool forbidden[26] = {};
  98. for (int to : unequal[root]) {
  99. to = dsu[0].find(to);
  100. if (color[to] != -1) forbidden[color[to]] = true;
  101. }
  102. int chosen = 0;
  103. while (chosen < 26 && forbidden[chosen]) ++chosen;
  104. if (chosen == 26) return 1; // The statement guarantees this cannot happen.
  105. color[root] = chosen;
  106. }
  107. string answer(n, 'a');
  108. for (int i = 0; i < n; ++i) answer[i] += color[dsu[0].find(i)];
  109. cout << answer << '\n';
  110. return 0;
  111. }