// O(N * log(N)) by doing a traversal of a segment tree (see get_kth). // Base segment tree implementation taken from // https://cp-algorithms.com/data_structures/segment_tree.html. #include #include #include #include void build_segment_tree(std::vector &tree, int v, int tl, int tr) { if (tl == tr) { tree[v] = 1; } else { int middle = (tl + tr) / 2; build_segment_tree(tree, v * 2, tl, middle); build_segment_tree(tree, v * 2 + 1, middle + 1, tr); tree[v] = tree[v * 2] + tree[v * 2 + 1]; } } int get_kth(std::vector &tree, int v, int tl, int tr, int k) { if (tl == tr) { return tl; } int tm = (tl + tr) / 2; int count_left = tree[v * 2]; int count_right = tree[v * 2 + 1]; if (count_left >= k) { return get_kth(tree, v * 2, tl, tm, k); } else { return get_kth(tree, v * 2 + 1, tm + 1, tr, k - count_left); } } void update(std::vector &tree, int v, int tl, int tr, int pos, int new_val) { if (tl == tr) { tree[v] = new_val; } else { int tm = (tl + tr) / 2; if (pos <= tm) update(tree, v * 2, tl, tm, pos, new_val); else update(tree, v * 2 + 1, tm + 1, tr, pos, new_val); tree[v] = tree[v * 2] + tree[v * 2 + 1]; } } std::array, 2> pick_players(const std::array, 2> &choices) { std::array, 2> teams; int N = choices[0].size() * 2; std::vector tree(4 * N); build_segment_tree(tree, 1, 0, N - 1); for (int i = 0; i < choices[0].size(); ++i) { for (int team = 0; team <= 1; team++) { int player = get_kth(tree, 1, 0, N - 1, choices[team][i]); update(tree, 1, 0, N - 1, player, 0); player++; teams[team].push_back(player); } } return teams; } int main() { int N; std::cin >> N; assert(N % 2 == 0); std::array, 2> choices; choices[0].reserve(N); choices[1].reserve(N); for (int i = 0; i < N; ++i) { int choice; std::cin >> choice; choices[i >= N / 2].push_back(choice); } auto teams = pick_players(choices); for (const auto &team : teams) { for (int player : team) { std::cout << player << " "; } std::cout << std::endl; } }