Best explained solution
Code

# Code
```cpp []
class Solution {
public:

    // Logic:
    // For each nums[idx] while traversing nums:
    // -> there will be some queries which already might have efefcted nums[idx] -> chosen_options
    // -> there will be some available queries which have not been explored yet -> available_options
    // -> if chosen_options did not reduce nums[idx] to 0, we explore available_options optimally
    // -> from available_options choose the option which have the max right_value (use max_heap)

    // before all this we sort queries so that we are sure that queries are processed in order
    int maxRemoval(vector<int>& nums, vector<vector<int>>& queries) {

        sort(queries.begin(), queries.end());

        // available_options -> stores the right_value for all the queries with effects nums[i]
        priority_queue<int> available_options;

        // chosen_options -> stores the right_value for all the queries we actually selected for 
        //                   nums[i] from available options
        priority_queue<int, vector<int>, greater<int>> chosen_options;


        // queries_used -> stores the number of queries actually used
        int queries_used = 0;

        // query_idx -> stores the index that will be processed in queries array
        int query_idx = 0;

        
        for(int idx = 0; idx < (int) nums.size(); idx++) {
            
            // for every nums[idx]:
            // we push right_values of all the queries which effect nums[idx] into available_options

            // Doubt: Why queries[query_idx][0] == idx?
            // As we sorted the queries the array, if we have observed any query whose left_value < idx,
            // that query's right_value will already be present in available_options (if not chosen),
            // or in chosen_options (if chosen).

            // for any query, q whose left_value < idx < right_value, q will already be present in the
            // queues as q would have been already processed. -> advantage of sorting the queires array
            while(query_idx < (int) queries.size() && queries[query_idx][0] == idx) {
                available_options.push(queries[query_idx][1]);
                query_idx++;
            }


            // for this idx we might have already chosen some options
            nums[idx] -= chosen_options.size();

            // if nums[idx] is still not 0, we explore available options
            while(nums[idx] > 0 && !available_options.empty() && available_options.top() >= idx) {
                // we used one query
                queries_used++;

                // the advantage of using max priority queue is that, we are sure this right_value
                // is the farthest available -> optimal choice

                // we transfer this right_value from available_options to chosen_options
                chosen_options.push(available_options.top());
                available_options.pop();

                // reduce nums[idx]
                nums[idx]--;
            }

            // if all available_options exhaust but nums[i] > 0 -> not possible to make zero array 
            if(nums[idx] > 0) return -1;

            // from chosen_options we remove redundant right_values -> remove right_value <= i
            // hence chosen_opions is a min heap
            while(!chosen_options.empty() && chosen_options.top() == idx) chosen_options.pop();
        }

        return (int) queries.size() - queries_used;
    }
};
```
['C++']