[DEBUG OUTPUT] PYTHON HEAPQ AND DICTIONARIES
IntuitionPut everything in heapq. Use dictionaries to keep track of active edits/removes.Complexity

Time complexity:
adding is log n. buidling as we go, is nlo
# Intuition
Put everything in heapq. Use dictionaries to keep track of active edits/removes.

# Complexity
- Time complexity:
adding is log n. buidling as we go, is nlogn. editing is log n to add a new entry. Removing is constant. ExecTop is worst case linear to remove everything in the heap.

- Space complexity:
Constant extra space is used for every possible task id. linear extra space is used for the heapq. Linear extra space is also used for the dict of task_ids to users.

# Code
```python3 []
class TaskManager:

    def __init__(self, tasks: List[List[int]]):
        # (userId, task_id, priority)
        self.processed_tasks = []
        self.task_ids_to_users = defaultdict(lambda: None)
        self.active_tasks = [ -1 for _ in range(100_000 + 1)]
        for each_task in tasks:
            self.processTask(each_task)
    
    def processTask(self, task: list[int]) -> None:
        user, task_id, priority = task
        task_and_priority = self.combineTaskAndPriority(task_id, priority)
        processed_triplet = (task_and_priority, task_id, priority)
        # print(f'ADDED {processed_triplet}')
        self.task_ids_to_users[task_id] = user
        self.active_tasks[task_id] = priority
        heapq.heappush(self.processed_tasks, processed_triplet)

    def combineTaskAndPriority(self, task_id: int, priority:int) -> int:
        combined = priority * 1E7
        combined += task_id
        return (combined * -1)

    def add(self, userId: int, task_id: int, priority: int) -> None:
        task = [userId, task_id, priority]
        self.processTask(task)

    def edit(self, task_id: int, new_priority: int) -> None:
        # print(f'need to make {task_id} into {new_priority}')
        user = self.task_ids_to_users[task_id]
        new_task = (user, task_id, new_priority)
        self.processTask(new_task)



    def rmv(self, task_id: int) -> None:
        # print(f'set {task_id} to inactive')
        self.active_tasks[task_id] = -1



    def execTop(self) -> int:
        # print(f'current state\n{self.processed_tasks}')
        if len(self.processed_tasks) == 0:
            # print(f'EMPTY')
            return -1
        next_task = heapq.heappop(self.processed_tasks)
        _, task_id, priority = next_task

        active_task_priority = self.active_tasks[task_id]
        if active_task_priority == priority:
            # print(f'IS ACTIVE: {next_task}')
            self.active_tasks[task_id] = -1
            return self.task_ids_to_users[task_id]
        # print(f'IS NOT ACTIVE: {next_task}')
        return self.execTop()


# Your TaskManager object will be instantiated and called as such:
# obj = TaskManager(tasks)
# obj.add(userId,task_id,priority)
# obj.edit(task_id,new_priority)
# obj.rmv(task_id)
# param_4 = obj.execTop()

# DEBUG OUTPUT
# Stdout
# ADDED (-100000101.0, 101, 10)
# ADDED (-200000102.0, 102, 20)
# ADDED (-150000103.0, 103, 15)
# ADDED (-50000104.0, 104, 5)
# need to make 102 into 8
# ADDED (-80000102.0, 102, 8)
# current state
# [(-200000102.0, 102, 20), (-100000101.0, 101, 10), (-150000103.0, 103, 15), (-50000104.0, 104, 5), (-80000102.0, 102, 8)]
# IS NOT ACTIVE: (-200000102.0, 102, 20)
# current state
# [(-150000103.0, 103, 15), (-100000101.0, 101, 10), (-80000102.0, 102, 8), (-50000104.0, 104, 5)]
# IS ACTIVE: (-150000103.0, 103, 15)
# set 101 to inactive
# ADDED (-150000105.0, 105, 15)
# current state
# [(-150000105.0, 105, 15), (-100000101.0, 101, 10), (-80000102.0, 102, 8), (-50000104.0, 104, 5)]
# IS ACTIVE: (-150000105.0, 105, 15)
```
['Python3']