from collections import deque

class Node:
    def __init__(self, value, parent):
        self.value = value
        self.parent = parent
        self.links = []
        self.anc_locked = 0
        self.dec_locked = 0
        self.uid = 0
        self.isLocked = False

    def add_links(self, children, parent):
        for child in children:
            self.links.append(Node(child, parent))

def print_tree(root):
    print(f"Parent: {root.value}")
    print("Child: ")
    for child in root.links:
        print(f"{child.value} anc_locked: {child.anc_locked} dec_locked: {child.dec_locked} isLocked: {child.isLocked} uid: {child.uid}")
    print("\n")
    for child in root.links:
        print_tree(child)

def build_tree(root, m, values):
    q = deque([root])
    idx = 1
    while q:
        current = q.popleft()
        if idx >= len(values):
            continue
        temp = []
        for i in range(idx, idx + m):
            if i < len(values):
                temp.append(values[i])
        current.add_links(temp, current)
        idx += m
        for child in current.links:
            q.append(child)    
    return root

class Tree:
    def __init__(self, root):
        self.root = root
        self.vton = {}

    def get_root(self):
        return self.root

    def fill_vton(self, node):
        if not node:
            return
        self.vton[node.value] = node
        for child in node.links:
            self.fill_vton(child)

    def inform_descendants(self, node, val):
        for child in node.links:
            child.anc_locked += val
            self.inform_descendants(child, val)

    def verify_descendants(self, node, uid, locked_nodes):
        if node.isLocked:
            if node.uid != uid:
                return False
            locked_nodes.append(node)
        if node.dec_locked == 0:
            return True
        for child in node.links:
            if not self.verify_descendants(child, uid, locked_nodes):
                return False
        return True

    def lock(self, value, uid):
        node = self.vton.get(value)
        if not node or node.isLocked or node.anc_locked != 0 or node.dec_locked != 0:
            return False
        cur = node.parent
        while cur:
            cur.dec_locked += 1
            cur = cur.parent
        self.inform_descendants(node, 1)
        node.isLocked = True
        node.uid = uid
        return True

    def unlock(self, value, uid):
        node = self.vton.get(value)
        if not node or not node.isLocked or node.uid != uid:
            return False
        cur = node.parent
        while cur:
            cur.dec_locked -= 1
            cur = cur.parent
        self.inform_descendants(node, -1)
        node.isLocked = False
        return True

    def upgrade(self, value, uid):
        node = self.vton.get(value)
        if not node or node.isLocked or node.anc_locked != 0 or node.dec_locked == 0:
            return False
        locked_nodes = []
        if self.verify_descendants(node, uid, locked_nodes):
            for locked_node in locked_nodes:
                self.unlock(locked_node.value, uid)
            self.lock(value, uid)
            return True
        return False

def main():
    n = int(input())
    m = int(input())
    q = int(input())
    
    values = [input().strip() for _ in range(n)]
    root = Node(values[0], None)
    root = build_tree(root, m, values)
    
    t = Tree(root)
    t.fill_vton(t.get_root())
    
    for _ in range(q):
        op, sq, uid = input().split()
        op = int(op)
        uid = int(uid)
        
        if op == 1:
            if t.lock(sq, uid):
                print("true")
            else:
                print("false")
        elif op == 2:
            if t.unlock(sq, uid):
                print("true")
            else:
                print("false")
        elif op == 3:
            if t.upgrade(sq, uid):
                print("true")
            else:
                print("false")

if __name__ == "__main__":
    main()

optimize this code i have a interview in which this code will be asked to optimize to it s finest and remove the reduntant code .

here is the question.
You have a world map represented as an M-Ary tree (sample tree below):

You need to define three operations on it:
lock(X, uid)
unlock(X, uid)
upgradeLock(X, uid)
Where X is the name of a node in the tree (which is unique), and uid is the user performing the operation.
Definitions for the Operations:
Lock(X, uid):
Lock takes exclusive access on the subtree rooted at X. Once lock(X, uid) succeeds:
lock(A, anyUserId) should fail (returns false), where A is a descendant of X.
lock(B, anyUserId) should fail (returns false), where X is a descendant of B.
Lock operation cannot be performed on a node that is already locked, i.e., lock(X, anyUserId) should fail (returns false).
Unlock(X, uid):
Unlock reverts what was done by the lock operation. It can only be called on the same node on which user uid had called a lock before. Returns true if successful.
UpgradeLock(X, uid):
This helps the user uid upgrade their lock to an ancestor node. It is only possible if the node X already has locked descendants and all of them are locked by the same user uid. Upgrade should fail if there is any node which is a descendant of X that is locked by a different user. A successful upgrade will "lock" the node. UpgradeLock must not violate the consistency model required by Lock/Unlock.
Notes:
The number of nodes in the tree, N, is very large, so optimize the time complexity for the above algorithms.
Input Format:


The first line contains the number of nodes in the tree (N).
The second line contains the number of children per node (m in an m-ary tree).
The third line contains the number of queries (Q).
Next N lines contain the NodeName (string) in the m-Ary Tree.
The next Q lines contain queries in the format: OperationType NodeName UserId.
Operation Type:
1 for Lock
2 for Unlock
3 for UpgradeLock
NodeName: The name of any node (unique) in the m-Ary Tree.
UserId: An integer representing a unique user.