#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

/*
 * This function partitions the array into three parts:
 * a) arr[l..i] contains all elements smaller than pivot
 * b) arr[i+1..j-1] contains all elements equal to pivot
 * c) arr[j..r] contains all elements greater than pivot
 */
void partition3Way(vector<int> &nums, int l, int r, int &i, int &j, long long &comp_count, long long &move_count)
{
    // To handle cases where array is sorted or nearly sorted
    int mid = l + (r - l) / 2;
    swap(nums[mid], nums[l]);
    move_count += 3;

    i = l, j = r + 1;
    int pivot = nums[l];

    while (true)
    {
        while (comp_count++, nums[++i] < pivot)
            if (i == r) break;

        while (comp_count++, pivot < nums[--j])
            if (j == l) break;

        // check if pointers cross
        if (i >= j) break;

        swap(nums[i], nums[j]);
        move_count += 3;
    }
    
    swap(nums[l], nums[j]);
    move_count += 3;
    i = j; // Return the pivot position
}


void quickSort3WayHelper(vector<int> &nums, int low, int high, long long &comp_count, long long &move_count)
{
    if (high <= low) return;

    int i, j;
    
    partition3Way(nums, low, high, i, j, comp_count, move_count);

    quickSort3WayHelper(nums, low, i - 1, comp_count, move_count);
    quickSort3WayHelper(nums, i + 1, high, comp_count, move_count);
}


/*
 * function   : implement 3-way quick sort
 * param nums : the vector to be sorted
 * param comp_count : count of comparisons
 * param move_count : count of moves
 * return     : ---
 */
void QuickSort3Way(vector<int> &nums, long long &comp_count, long long &move_count)
{
    if (nums.empty()) return;
    // For better performance on random data, shuffle is recommended, but we'll skip for this experiment
    // random_shuffle(nums.begin(), nums.end()); 
    quickSort3WayHelper(nums, 0, nums.size() - 1, comp_count, move_count);
}
