TreeSet + HashMap  
https://carefree-ladka.github.io/js.enigma/docs/DSA/TreeSet
https://carefree-ladka.github.io/js.enigma/docs/DSA/TreeMapYou can find custom class for SortedList,
https://carefree-ladka.github.io/js.enigma/docs/DSA/TreeSet
https://carefree-ladka.github.io/js.enigma/docs/DSA/TreeMap


You can find custom class for SortedList, TreetMap, TreeSet (using Red Black Tree) etc for JS on the above site.  I use it for my last minute prep.

**TC :**

add: O(log N)
edit: O(log N)
rmv: O(log N)
execTop: O(log N)


**Dry run:**


```plaintext

init : taskManager = new TaskManager([[1, 101, 10], [2, 102, 20], [3, 103, 15]]);

First Operation: (add(4, 104, 5))

taskManager.add(4, 104, 5);

Map :     { 101 => [ 1, 10 ], 102 => [ 2, 20 ], 103 => [ 3, 15 ] }

TreeSet:  [ [ 20, 102 ], [ 15, 103 ], [ 10, 101 ] ]

---
Second Operation: (edit(102, 8))

Map :     { 101 => [ 1, 10 ], 102 => [ 2, 20 ], 103 => [ 3, 15 ] }

TreeSet:  [ [ 20, 102 ], [ 15, 103 ], [ 10, 101 ] ]

execTop : 3

....rest

```
---

```javascript []
class TreeNode {
  constructor(value) {
    this.value = value;
    this.left = null;
    this.right = null;
    this.height = 1;
  }
}

class TreeSet {
  constructor(comparator = (a, b) => a - b) {
    this.root = null;
    this.size = 0;
    this.comparator = comparator;
  }

  #getHeight(node) {
    return node ? node.height : 0;
  }

  #getBalance(node) {
    return node ? this.#getHeight(node.left) - this.#getHeight(node.right) : 0;
  }

  #rightRotate(y) {
    const x = y.left;
    const T2 = x.right;

    x.right = y;
    y.left = T2;

    y.height = Math.max(this.#getHeight(y.left), this.#getHeight(y.right)) + 1;
    x.height = Math.max(this.#getHeight(x.left), this.#getHeight(x.right)) + 1;

    return x;
  }

  #leftRotate(x) {
    const y = x.right;
    const T2 = y.left;

    y.left = x;
    x.right = T2;

    x.height = Math.max(this.#getHeight(x.left), this.#getHeight(x.right)) + 1;
    y.height = Math.max(this.#getHeight(y.left), this.#getHeight(y.right)) + 1;

    return y;
  }

  // Add value to set
  add(value) {
    const result = !this.has(value);
    if (result) {
      this.root = this.#add(this.root, value);
      this.size++;
    }
    return result;
  }

  #add(node, value) {
    if (!node) return new TreeNode(value);

    const cmp = this.comparator(value, node.value);
    if (cmp < 0) {
      node.left = this.#add(node.left, value);
    } else if (cmp > 0) {
      node.right = this.#add(node.right, value);
    } else {
      return node;
    }

    node.height = Math.max(this.#getHeight(node.left), this.#getHeight(node.right)) + 1;
    const balance = this.#getBalance(node);

    // Balance the tree
    if (balance > 1 && this.comparator(value, node.left.value) < 0) {
      return this.#rightRotate(node);
    }
    if (balance < -1 && this.comparator(value, node.right.value) > 0) {
      return this.#leftRotate(node);
    }
    if (balance > 1 && this.comparator(value, node.left.value) > 0) {
      node.left = this.#leftRotate(node.left);
      return this.#rightRotate(node);
    }
    if (balance < -1 && this.comparator(value, node.right.value) < 0) {
      node.right = this.#rightRotate(node.right);
      return this.#leftRotate(node);
    }

    return node;
  }

  // Remove value from set
  remove(value) {
    const result = this.has(value);
    if (result) {
      this.root = this.#remove(this.root, value);
      this.size--;
    }
    return result;
  }

  #remove(node, value) {
    if (!node) return null;

    const cmp = this.comparator(value, node.value);
    if (cmp < 0) {
      node.left = this.#remove(node.left, value);
    } else if (cmp > 0) {
      node.right = this.#remove(node.right, value);
    } else {
      if (!node.left || !node.right) {
        return node.left || node.right;
      }
      const temp = this.#getMin(node.right);
      node.value = temp.value;
      node.right = this.#remove(node.right, temp.value);
    }

    node.height = Math.max(this.#getHeight(node.left), this.#getHeight(node.right)) + 1;
    const balance = this.#getBalance(node);

    if (balance > 1 && this.#getBalance(node.left) >= 0) {
      return this.#rightRotate(node);
    }
    if (balance > 1 && this.#getBalance(node.left) < 0) {
      node.left = this.#leftRotate(node.left);
      return this.#rightRotate(node);
    }
    if (balance < -1 && this.#getBalance(node.right) <= 0) {
      return this.#leftRotate(node);
    }
    if (balance < -1 && this.#getBalance(node.right) > 0) {
      node.right = this.#rightRotate(node.right);
      return this.#leftRotate(node);
    }

    return node;
  }

  // Check if value exists
  has(value) {
    return this.#find(this.root, value) !== null;
  }

  #find(node, value) {
    if (!node) return null;
    const cmp = this.comparator(value, node.value);
    if (cmp === 0) return node;
    return cmp < 0 ? this.#find(node.left, value) : this.#find(node.right, value);
  }

  #getMin(node) {
    while (node.left) {
      node = node.left;
    }
    return node;
  }

  #getMax(node) {
    while (node.right) {
      node = node.right;
    }
    return node;
  }

  // Get smallest value greater than or equal to given value
  ceiling(value) {
    let node = this.root;
    let result = null;

    while (node) {
      const cmp = this.comparator(value, node.value);
      if (cmp === 0) return node.value;
      if (cmp < 0) {
        result = node.value;
        node = node.left;
      } else {
        node = node.right;
      }
    }

    return result;
  }

  // Get largest value less than or equal to given value
  floor(value) {
    let node = this.root;
    let result = null;

    while (node) {
      const cmp = this.comparator(value, node.value);
      if (cmp === 0) return node.value;
      if (cmp < 0) {
        node = node.left;
      } else {
        result = node.value;
        node = node.right;
      }
    }

    return result;
  }

  // Get smallest value in set
  first() {
    return this.root ? this.#getMin(this.root).value : undefined;
  }

  // Get largest value in set
  last() {
    return this.root ? this.#getMax(this.root).value : undefined;
  }

  // Get set size
  getSize() {
    return this.size;
  }

  // Check if set is empty
  isEmpty() {
    return this.size === 0;
  }

  // Clear all values
  clear() {
    this.root = null;
    this.size = 0;
  }

  // Convert to array (in-order traversal)
  toArray() {
    const result = [];
    this.#inorderTraversal(this.root, value => result.push(value));
    return result;
  }

  #inorderTraversal(node, callback) {
    if (node) {
      this.#inorderTraversal(node.left, callback);
      callback(node.value);
      this.#inorderTraversal(node.right, callback);
    }
  }

  // Iterator
  *[Symbol.iterator]() {
    yield* this.#iterate(this.root);
  }

  *#iterate(node) {
    if (node) {
      yield* this.#iterate(node.left);
      yield node.value;
      yield* this.#iterate(node.right);
    }
  }
}


// Task Manager Class 

class TaskManager {
  constructor(tasks) {
    this.d = new Map();
    this.st = new TreeSet((a, b) => a[0] === b[0] ? b[1] - a[1] : b[0] - a[0]);

    for (const task of tasks) {
      this.add(task[0], task[1], task[2]);
    }
  }

  add(userId, taskId, priority) {
    this.d.set(taskId, [userId, priority]);
    this.st.add([priority, taskId]);
  }

  edit(taskId, newPriority) {
    const [userId, priority] = this.d.get(taskId);
    this.st.remove([priority, taskId]);
    this.st.add([newPriority, taskId]);
    this.d.set(taskId, [userId, newPriority]);
  }

  rmv(taskId) {
    const [userId, priority] = this.d.get(taskId);
    this.d.delete(taskId);
    this.st.remove([priority, taskId]);
  }

  execTop() {
    if (this.st.isEmpty()) {
      return -1;
    }
    const [priority, taskId] = this.st.first();
    const [userId] = this.d.get(taskId);
    this.st.remove([priority, taskId]);
    this.d.delete(taskId);
    return userId;
  }
}

```
['Design', 'Ordered Set', 'JavaScript']