Two Heapq
IntuitionThink of the queries as closed intervals (inclusive of endpoints).  We will select a subset of the intervals to cover nums.  For each index i in range(
# Intuition
<!-- Describe your first thoughts on how to solve this problem. -->
Think of the queries as closed intervals (inclusive of endpoints).  We will select a subset of the intervals to cover `nums`.  For each index `i` in `range(len(nums))`, the number of selected intervals that cover `i` should be no less than `nums[i]`.  Sort the `queries` so that the intervals are presented from left to right on the number line.

Use two heaps, one min heap, and another max heap.  Both heaps store intervals.  The min heap `minH` caches the intervals that are previously selected, and maintains that `minH[0]` has the smallest right endpoint.  The max heap `maxH` stores candidiate intervals that may be selected (but not yet selected), and maintains that `maxH[0]` has the greatest right endpoint.  Among the candidate, we greedily select `maxH[0]`, as it potentially covers more points to the right.

# Approach
<!-- Describe your approach to solving the problem. -->

For each `i`, and corresponding `num = nums[i]`, proceed in a loop as follows.

1. As long as `minH` contains previously used intervals, if the top interval fails to cover `i`, pop `minH`.
2. After step 1, check if there are enough intervals in `minH` to cover `i` for `num` times.  If so, simply continue to next loop if needed.
3. Now we know that we must select more available intervals from `queries` to cover `i`.  Look at index `q` pointing to the next available interval in `queries`.  As long as it cannot cover the current `i`, skip it.
4. As long as the next interval may cover `i`, push it into `maxH` as a candidate.
5. As long as there are candidates in `maxH`, we greedily pop the top out of `maxH` and push the result into `minH`, while incrementing `used`.  We do this as long as we need more intervals to cover `i`.
6. After step 5, if we cannot obtain enough intervals to cover `i`, return `-1`; otherwise, go to next loop if needed.

The answer is `nq - used`.

# Complexity
- Time complexity:
<!-- Add your time complexity here, e.g. $$O(n)$$ -->
$O(n)$

- Space complexity:
<!-- Add your space complexity here, e.g. $$O(n)$$ -->
$O(n)$

# Code
```python3 []
class MinElem:
    def __init__(self, left, rite):
        self.left = left
        self.rite = rite
    def __lt__(self, other):
        return self.rite < other.rite

class MaxElem:
    def __init__(self, left, rite):
        self.left = left
        self.rite = rite
    def __lt__(self, other):
        return self.rite > other.rite

class Solution:
    def maxRemoval(self, nums: List[int], queries: List[List[int]]) -> int:
        queries.sort()  # queries are intervals, now sorted
        nq = len(queries)
        q = 0  # pointer to q-th query to be considered
        maxH = []  # candidate intervals for reducing each num
        minH = []  # intervals actually used to reduce each num
        used = 0
        for i, num in enumerate(nums):  # try to reduce each num
            # remove intervals that have been used but cannot help reduce the current num
            while minH and minH[0].rite < i: heappop(minH)
            if num <= len(minH): continue  # no need to consider any more interval
            while q < nq and queries[q][1] < i: q += 1  # skip non-usable queries
            while q < nq and queries[q][0] <= i:
                left, rite = queries[q]
                heappush(maxH, MaxElem(left, rite))
                q += 1
            while maxH and len(minH) < num:
                interval = heappop(maxH)
                if i < interval.left or interval.rite < i: continue
                heappush(minH, MinElem(interval.left, interval.rite))
                used += 1
            if len(minH) < num: return -1
        return nq - used

            

```
['Python3']