Editorial for Riolku's Mock CCC S5 - Keen Keener Multiset
Submitting an official solution before solving the problem yourself is a bannable offence.
Author:
Subtask 1
This subtask was intended to reward brute force solutions.
Time Complexity:
Subtask 2
Maintaining a dynamic prefix-XOR array suffices.
Time Complexity:
Subtask 3
A trie can be augmented to support range XOR queries. To deal with type operations, use a lazy value. If the current bit is , swap the children of the node. This solution can be adapted to remove the laziness entirely.
Time Complexity:
Subtask 4
Here we present a SQRT decomposition solution on the values. Let be the block size where where .
We'll focus on type operations as type and operations are quite simple and only require maintaining a cumulative XOR value in each block along with a frequency array.
As the block size is a power of , we can consider the top and bottom bits independently, which means that type operations only require moving around blocks and changing a flag which denotes the cumulative XOR value of the bottom bits in the block (and brute forcing the update in partially covered blocks). The problem now is when two blocks are moved to the same position, we have to merge them as having multiple blocks that occupy the same range of values can result in quadratic time complexity.
However, we can show that the total number of merges is if we do not merge two blocks when one of them is empty, meaning that we can brute force the merges. Consider the following:
- Initially, there will be at most blocks with values
- Each type query can create at most non-empty block
- Each type query can create at most non-empty blocks. The proof is the following:
- Non-empty blocks can only be created from values in partially covered blocks where the update is brute forced
- Obviously, the number of partially covered blocks is at most
- As the block size is a power of , the top bits of the values that are XORed in each partially covered block will all be the same after being XORed. This means that they will all fall into the same new block
- Each merge removes one non-empty block
Time Complexity:
Comments
There's a simple solution for subtask 4; it's essentially the same as the SQRT solution given, but stores trie nodes with lazy xor updates, and then merges trie nodes instead of blocks. In particular, to do operation 2:
The split step will create at most new nodes, and each nontrivial step of the merge will delete one trie node, so the total runtime amortizes to .
We considered this pre-contest, but couldn't prove the runtime as easily. That said, this solution is very clean, and I love the split-merge lazy trie approach, so thanks for your comment.
Note: DMOJ uses
~
, not$
, for math, and you can use\mathcal
for nice time complexities.