Kth Ancestor of a Tree Node

hard tree binary lifting

Problem

You are given a tree with n nodes numbered 0 to n − 1, where node 0 is the root and parent[i] is the parent of node i (parent[0] = −1). Design a data structure answering queries getKthAncestor(node, k): the node reached after walking k steps up toward the root, or −1 if node has fewer than k ancestors.

With up to 5·10⁴ nodes and 5·10⁴ queries (1 ≤ k ≤ n), and trees that can be long chains, walking up one parent at a time is too slow — each query needs to run in roughly logarithmic time.

Inputparent = [-1,0,0,1,1,2,2]; getKthAncestor(3,1), getKthAncestor(5,2), getKthAncestor(6,3)
Output1, 0, -1
One step above 3 is 1, two steps above 5 is the root 0, and 6 has only two ancestors so a third does not exist.

class TreeAncestor:
    def __init__(self, n, parent):
        self.LOG = n.bit_length()
        up = [parent[:]]                  # level 0 = direct parents
        for j in range(1, self.LOG):
            prev = up[j - 1]
            up.append([-1 if prev[v] == -1 else prev[prev[v]]
                       for v in range(n)])
        self.up = up

    def get_kth_ancestor(self, node, k):
        for j in range(self.LOG):
            if k >> j & 1:
                node = self.up[j][node]
                if node == -1:
                    return -1
        return node
class TreeAncestor {
  constructor(n, parent) {
    this.LOG = 32 - Math.clz32(n);
    this.up = [parent.slice()];          // level 0 = direct parents
    for (let j = 1; j < this.LOG; j++) {
      const prev = this.up[j - 1], row = [];
      for (let v = 0; v < n; v++)
        row.push(prev[v] === -1 ? -1 : prev[prev[v]]);
      this.up.push(row);
    }
  }

  getKthAncestor(node, k) {
    for (let j = 0; j < this.LOG; j++) {
      if (k >> j & 1) {
        node = this.up[j][node];
        if (node === -1) return -1;
      }
    }
    return node;
  }
}
class TreeAncestor {
    private final int LOG;
    private final int[][] up;

    public TreeAncestor(int n, int[] parent) {
        LOG = 32 - Integer.numberOfLeadingZeros(n);
        up = new int[LOG][n];
        up[0] = parent.clone();          // level 0 = direct parents
        for (int j = 1; j < LOG; j++)
            for (int v = 0; v < n; v++)
                up[j][v] = up[j-1][v] == -1
                    ? -1 : up[j-1][up[j-1][v]];
    }

    public int getKthAncestor(int node, int k) {
        for (int j = 0; j < LOG; j++) {
            if ((k >> j & 1) == 1) {
                node = up[j][node];
                if (node == -1) return -1;
            }
        }
        return node;
    }
}
class TreeAncestor {
    int LOG;
    vector<vector<int>> up;
public:
    TreeAncestor(int n, vector<int>& parent) {
        LOG = 32 - __builtin_clz(n);
        up.assign(LOG, vector<int>(n, -1));
        up[0] = parent;                  // level 0 = direct parents
        for (int j = 1; j < LOG; j++)
            for (int v = 0; v < n; v++)
                if (up[j-1][v] != -1)
                    up[j][v] = up[j-1][up[j-1][v]];
    }

    int getKthAncestor(int node, int k) {
        for (int j = 0; j < LOG; j++) {
            if (k >> j & 1) {
                node = up[j][node];
                if (node == -1) return -1;
            }
        }
        return node;
    }
};
Time: O(n log n) build, O(log n) per query Space: O(n log n)