code: private void updateBlocks() {
          for (Block<S, L> block : splitBlocks) {
              // Ignore blocks that have no elements in their sub blocks.
              int inSubBlocks = block.getElementsInSubBlocks();
              if (inSubBlocks == 0) {
                  continue;
              }
  
              boolean blockRemains = (inSubBlocks < block.size());
  
              boolean reuseBlock = !blockRemains;
  
              List<UnorderedCollection<State<S, L>>> subBlocks = block.getSubBlocks();
              // If there is only one sub block which contains all elements of
              // the block, then no split needs to be performed.
              if (!blockRemains && subBlocks.size() == 1) {
                  block.clearSubBlocks();
                  continue;
              }
  
              Iterator<UnorderedCollection<State<S, L>>> subBlockIt = subBlocks.iterator();
  
              if (reuseBlock) {
                  UnorderedCollection<State<S, L>> first = subBlockIt.next();
                  block.getStates().swap(first);
                  updateBlockReferences(block);
              }
  
              while (subBlockIt.hasNext()) {
                  UnorderedCollection<State<S, L>> subBlockStates = subBlockIt.next();
  
                  if (blockRemains) {
                      for (State<S, L> state : subBlockStates) {
                          block.removeState(state.getBlockReference());
                      }
                  }
  
                  Block<S, L> subBlock = new Block<>(numBlocks++, subBlockStates);
                  updateBlockReferences(subBlock);
                  newBlocks.add(subBlock);
                  addToPartition(subBlock);
              }
  
              newBlocks.add(block);
              block.clearSubBlocks();
  
              // If the split block previously was in the queue, add all newly
              // created blocks to the queue. Otherwise, it's enough to add
              // all but the largest
              if (removeFromSplitterQueue(block)) {
                  addAllToSplitterQueue(newBlocks);
              } else {
                  addAllButLargest(newBlocks);
              }
              newBlocks.clear();
          }
  
          splitBlocks.clear();
      }
docs: This method performs the actual splitting of blocks, using the sub block information stored in each block
  object.