1const LOG = 4; // 2^3=8 足够覆盖树深
2const fa = Array.from({ length: n }, () => new Array(LOG).fill(-1));
3for (let u = 0; u < n; u++) fa[u][0] = parent[u];
4for (let k = 1; k < LOG; k++)
5 for (let u = 0; u < n; u++)
6 fa[u][k] = fa[u][k-1] < 0 ? -1 : fa[fa[u][k-1]][k-1];
7function lca(u, v) {
8 if (depth[u] < depth[v]) [u, v] = [v, u];
9 for (let k = 0, d = depth[u]-depth[v]; d > 0; k++, d >>= 1)
10 if (d & 1) u = fa[u][k]; // 二进制分解跳祖先
11 if (u === v) return u;
12 for (let k = LOG-1; k >= 0; k--)
13 if (fa[u][k] !== fa[v][k]) { u = fa[u][k]; v = fa[v][k]; }
14 return fa[u][0];
15}