DarkNerd | ✅
IntuitionWe need to manage tasks where each task has a taskId, userId, and priority. The system should efficiently support the following operations:
Add a new t
## **Intuition**
We need to manage tasks where each task has a `taskId`, `userId`, and `priority`. The system should efficiently support the following operations:
1. **Add** a new task.
2. **Edit** the priority of an existing task.
3. **Remove** a task.
4. **Execute the highest priority task** (removing it after execution).

To efficiently handle tasks based on priority, we use two data structures:
- **`unordered_map<int, pair<int, int>> ttoup`**: This maps `taskId` to `{userId, priority}`. It helps in quick lookup and modification of a task’s details.
- **`map<int, set<int>> ptot`**: This stores tasks sorted by priority, where each priority maps to a **set** of `taskId`s (sorted automatically). The highest priority task is always available at the **end** of this map.

---

## **Approach**
### **1. Adding a Task `add`**
- Store `{userId, priority}` in `ttoup` using `taskId` as the key.
- Insert the `taskId` into the `set` of tasks corresponding to its `priority` inside `ptot`.

🔹 **Data Structures Used:**
- **`unordered_map` `ttoup`** for quick access to task details.
- **`map` `ptot`** to store tasks sorted by priority.

---

### **2. Editing a Task’s Priority (`edit`)**
- Find the **current priority** of the task using `ttoup`.
- Remove `taskId` from its old priority set inside `ptot`.
- If the old priority set becomes empty, erase it from `ptot`.
- Insert the `taskId` into the new priority set inside `ptot`.
- Update the `priority` in `ttoup`.

🔹 **Why is `map<int, set<int>> ptot` used?**
- The **`set<int>`** ensures that tasks remain sorted within each priority group.
- The **`map<int, set<int>>`** keeps all priorities sorted in ascending order.

---

### **3. Removing a Task `rmv`**
- Find the **priority** of the task from `ttoup`.
- Remove `taskId` from its corresponding `set` in `ptot`.
- If the priority set becomes empty, erase that priority from `ptot`.
- Remove the task from `ttoup`.

---

### **4. Executing the Highest Priority Task `execTop`**
- Get the **last** element in `ptot` (which has the highest priority).
- Within that priority, get the **last task** (since tasks are sorted in a `set`).
- Retrieve the **`userId`** of that task from `ttoup`.
- Remove this task from both `ptot` and `ttoup`.
- Return the `userId`.

---

## **Complexity Analysis**
### **Time Complexity**
| Operation | Complexity |
|-----------|------------|
| **Adding a Task `add`** | $$O(\log P + \log T)$$ |
| **Editing a Task’s Priority `edit`** | $$O(\log P + \log T)$$ |
| **Removing a Task `rmv`** | $$O(\log P + \log T)$$ |
| **Executing the Highest Priority Task `execTop`** | $$O(\log P + \log T)$$ |

**Why?**
- **`unordered_map` operations `ttoup`** take $$O(1)$$ time.
- **`map<int, set<int>> ptot` uses `log` operations:**
  - Finding a priority in `map` takes $$O(\log P)$$ `binary search`.
  - Inserting/removing a `taskId` in `set<int>` takes $$O(\log T)$$.

### **Space Complexity**
- **`ttoup` stores one entry per task** $$\Rightarrow O(N)$$
- **`ptot` stores at most `N` priorities, each with at most `N` tasks** $$\Rightarrow O(N)$$

**Total Space Complexity:** $$O(N)$$

---

# Code
```cpp []
class TaskManager {
public:
    unordered_map<int, pair<int, int>> ttoup;
    map<int, set<int>> ptot;
    TaskManager(vector<vector<int>>& tasks) {
        for(auto i:tasks) add(i[0], i[1], i[2]);
    }
    
    void add(int userId, int taskId, int priority) {
        ttoup[taskId]={userId, priority};
        ptot[priority].insert(taskId);
    }
    
    void edit(int taskId, int newPriority) {
        int& p=ttoup[taskId].second;
        if(ptot[p].size()==1) ptot.erase(p);
        else ptot[p].erase(taskId);

        ptot[newPriority].insert(taskId);
        p=newPriority;
    }
    
    void rmv(int taskId) {
        int p=ttoup[taskId].second;
        if(ptot[p].size()==1) ptot.erase(p);
        else ptot[p].erase(taskId);
        ttoup.erase(taskId);
    }
    
    int execTop() {
        if(ptot.empty()) return -1;
        int task = *rbegin(rbegin(ptot)->second);
        int user = ttoup[task].first;
        rmv(task);
        return user;
    }
};

/**
 * Your TaskManager object will be instantiated and called as such:
 * TaskManager* obj = new TaskManager(tasks);
 * obj->add(userId,taskId,priority);
 * obj->edit(taskId,newPriority);
 * obj->rmv(taskId);
 * int param_4 = obj->execTop();
 */
```
['C++']