<p>You are given an array of <code>events</code> where <code>events[i] = [startDay<sub>i</sub>, endDay<sub>i</sub>]</code>. Every event <code>i</code> starts at <code>startDay<sub>i</sub></code><sub> </sub>and ends at <code>endDay<sub>i</sub></code>.</p>

<p>You can attend an event <code>i</code> at any day <code>d</code> where <code>startTime<sub>i</sub> &lt;= d &lt;= endTime<sub>i</sub></code>. You can only attend one event at any time <code>d</code>.</p>

<p>Return <em>the maximum number of events you can attend</em>.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2020/02/05/e1.png" style="width: 400px; height: 267px;" />
<pre>
<strong>Input:</strong> events = [[1,2],[2,3],[3,4]]
<strong>Output:</strong> 3
<strong>Explanation:</strong> You can attend all the three events.
One way to attend them all is as shown.
Attend the first event on day 1.
Attend the second event on day 2.
Attend the third event on day 3.
</pre>

<p><strong class="example">Example 2:</strong></p>

<pre>
<strong>Input:</strong> events= [[1,2],[2,3],[3,4],[1,2]]
<strong>Output:</strong> 4
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>1 &lt;= events.length &lt;= 10<sup>5</sup></code></li>
	<li><code>events[i].length == 2</code></li>
	<li><code>1 &lt;= startDay<sub>i</sub> &lt;= endDay<sub>i</sub> &lt;= 10<sup>5</sup></code></li>
</ul>

# class Solution:
#     def maxEvents(self, events: List[List[int]]) -> int:
#         n = len(events)
#         events = sorted(events)    # sort based on the start day
#         minhpq = []                # min heap to store finishing time of events ascendingly 
#         today = 0                  # pointer for current day
#         i = 0                      # pointer for events
#         count = 0
        
#         while minhpq or i < n:
#             # if empty, then set today to start time of event[i]
#             if not minhpq:
#                 today = events[i][0]

#             # 1. add the end time of every task with the same starting day as of today
#             while i < n and events[i][0] == today:
#                 end = events[i][1]
#                 heappush(minhpq, end)
#                 i += 1

#             # 2. greedily finish the task with earliest time
#             heappop(minhpq)
#             count += 1

#             # next valid day
#             today += 1  

#             # 3. clean up; remove any task finishes before valid today pointer
#             while minhpq and minhpq[0] < today:
#                 heappop(minhpq)

#         return count


class Solution:
    def maxEvents(self, events: List[List[int]]) -> int:
        min_heap = []  # min heap of events end time
        events.sort(key = lambda e: e[0])  # sort events by start time

        i = count_events_attended = cur_day = 0
        while i < len(events) or min_heap:
            if not min_heap:
                cur_day = events[i][0]
            
            # add open events for cur_day
            while i < len(events) and events[i][0] <= cur_day:
                heappush(min_heap, events[i][1])
                i += 1

            heappop(min_heap)  # attend the event ends earliest
            count_events_attended += 1

            cur_day += 1
            # remove close events for cur_day
            while min_heap and min_heap[0] < cur_day:
                heappop(min_heap)

        return count_events_attended


        



        
#         0, None

#   1, 2    1, None
# 2,3, 2, 2                2, 3, 1, None
63400