Problem: Maximum Number of Eaten Apples

There is a special kind of apple tree that grows apples every day for `n`
days. On the `ith` day, the tree grows `apples[i]` apples that will rot after
`days[i]` days, that is on day `i + days[i]` the apples will be rotten and
cannot be eaten. On some days, the apple tree does not grow any apples, which
are denoted by `apples[i] == 0` and `days[i] == 0`.

You decided to eat at most one apple a day (to keep the doctors away). Note
that you can keep eating after the first `n` days.

Given two integer arrays `days` and `apples` of length `n`, return the maximum
number of apples you can eat.


Python solution:
import math
import itertools
import bisect
import collections
import string
import heapq
import functools
import sortedcontainers
from typing import List, Dict, Tuple, Iterator

class Solution:
  def eatenApples(self, apples: List[int], days: List[int]) -> int:
    n = len(apples)
    ans = 0
    minHeap = []

    i = 0
    while i < n or minHeap:
      while minHeap and minHeap[0][0] <= i:
        heapq.heappop(minHeap)
      if i < n and apples[i] > 0:
        heapq.heappush(minHeap, (i + days[i], apples[i]))
      if minHeap:
        rottenDay, numApples = heapq.heappop(minHeap)
        if numApples > 1:
          heapq.heappush(minHeap, (rottenDay, numApples - 1))
        ans += 1
      i += 1

    return ans


Java solution:
class Solution {
  public int eatenApples(int[] apples, int[] days) {
    final int n = apples.length;
    int ans = 0;
    // (the rotten day, the number of apples)
    Queue<Pair<Integer, Integer>> minHeap =
        new PriorityQueue<>(Comparator.comparingInt(Pair::getKey));

    for (int i = 0; i < n || !minHeap.isEmpty(); ++i) {
      // Remove the rotten apples.
      while (!minHeap.isEmpty() && minHeap.peek().getKey() <= i)
        minHeap.poll();
      // Add today's apples.
      if (i < n && apples[i] > 0)
        minHeap.offer(new Pair<>(i + days[i], apples[i]));
      // Eat one apple today.
      if (!minHeap.isEmpty()) {
        final int rottenDay = minHeap.peek().getKey();
        final int numApples = minHeap.poll().getValue();
        if (numApples > 1)
          minHeap.offer(new Pair<>(rottenDay, numApples - 1));
        ++ans;
      }
    }

    return ans;
  }
}


C++ solution:
class Solution {
 public:
  int eatenApples(vector<int>& apples, vector<int>& days) {
    const int n = apples.size();
    int ans = 0;
    using P = pair<int, int>;  // (the rotten day, the number of apples)
    priority_queue<P, vector<P>, greater<>> minHeap;

    for (int i = 0; i < n || !minHeap.empty(); ++i) {  // i := day
      // Remove the rotten apples.
      while (!minHeap.empty() && minHeap.top().first <= i)
        minHeap.pop();
      // Add today's apples.
      if (i < n && apples[i] > 0)
        minHeap.emplace(i + days[i], apples[i]);
      // Eat one apple today.
      if (!minHeap.empty()) {
        const auto [rottenDay, numApples] = minHeap.top();
        minHeap.pop();
        if (numApples > 1)
          minHeap.emplace(rottenDay, numApples - 1);
        ++ans;
      }
    }

    return ans;
  }
};