Binary search to keap priorities sorted
IntuitionI built it from scratch. No fancy methods or objects used.Approach
all task are stored and hashed in dict (task:(priority, userId))
priority is stored
# Intuition
<!-- Describe your first thoughts on how to solve this problem. -->
I built it from scratch. No fancy methods or objects used. 

# Approach
<!-- Describe your approach to solving the problem. -->
- all task are stored and hashed in dict (task:(priority, userId))
- priority is stored in a list that is keeped sorted [(priority,task)]
- to keep list sorted I build two additional functions. First to find and pop given priority, second to find propper index and insert given priority. Both are build based on binary search

# Complexity
- Time complexity:
<!-- Add your time complexity here, e.g. $$O(n)$$ -->
init - O(NlogN) - initial sorting
add  - O(logN) - binary search to insert priority
edit - O(logN) - binary search to remove old and insert new priority
rmv  - O(logN) - binary search to find priority
execTop - O(1) - Just pop top priority and find task in dict.

- Space complexity:
<!-- Add your space complexity here, e.g. $$O(n)$$ -->
O(n) - data stored in a dict and a list

# Code
```python3 []
class TaskManager:

    def __init__(self, tasks: List[List[int]]):
        self.priorities = [] #sorted list of (priority, taskId)
        self.tasks = {} # taskId : (priority, userId)
        for user, task, priority in tasks:
            self.tasks[task] = (priority, user)
            self.priorities.append((priority,task))
        self.priorities.sort()
        print(self.priorities)

        

    def add(self, userId: int, taskId: int, priority: int) -> None:
        self.tasks[taskId] = (priority, userId)
        self.insert(taskId, priority)

    def edit(self, taskId: int, newPriority: int) -> None:
        priority, user = self.tasks[taskId]
        self.tasks[taskId] = (newPriority, user)
        self.find_and_pop(taskId, priority)
        self.insert(taskId, newPriority)

    def rmv(self, taskId: int) -> None:
        priority, user = self.tasks.pop(taskId)
        self.find_and_pop(taskId, priority)

    def execTop(self) -> int:
        #returns User with top priority task and a higher task if a draw
        if not self.priorities:
            return - 1
        priority, task = self.priorities.pop()
        priority, user = self.tasks.pop(task)
        return user
    
    def find_and_pop(self, taskId: int, priority: int) -> None:
        l, r = 0, len(self.priorities)
        while l <= r:
            mid = l + (r-l)//2
            if self.priorities[mid][0] == priority:
                if self.priorities[mid][1] == taskId:
                    self.priorities.pop(mid)
                    return
                elif self.priorities[mid][1] > taskId:
                    r = mid - 1
                else:
                    l = mid + 1
            elif self.priorities[mid][0] > priority:
                r = mid - 1
            else:
                l = mid + 1

    def insert(self, taskId: int, priority: int) -> None:
        l, r = 0, len(self.priorities)
        while l < r:
            mid = l + (r-l)//2
            if self.priorities[mid][0] == priority:
                if self.priorities[mid][1] > taskId:
                    r = mid
                else:
                    l = mid + 1
            elif self.priorities[mid][0] > priority:
                r = mid
            else:
                l = mid + 1
        
        self.priorities.insert(r, (priority, taskId))
        return
```
['Binary Search', 'Python3']