#3590
Hard Algorithms Kth smallest path xor sum
Array Tree Depth-First Search Ordered Set
29.0% acceptance
Mar 9, 2026
27
11
You are given an undirected tree rooted at node 0. Each node i has a value vals[i].
The path XOR sum from root to node u is XOR of all vals[i] on that path.
For each query [u, k], find the kth smallest distinct path XOR sum in subtree of u.
Return -1 if fewer than k distinct XOR sums exist.
Solution
Rust
Time O(n * m)
Space O(n * m)
fn ch_alloc(ch: &mut [[u32; 2]], ct: &mut [u32], pool: &mut u32, free: &mut Vec<u32>) -> u32 {
if let Some(id) = free.pop() {
ch[id as usize] = [0, 0];
ct[id as usize] = 0;
id
} else {
let id = *pool;
*pool += 1;
id
}
}
fn ch_merge(a: u32, b: u32, ch: &mut [[u32; 2]], ct: &mut [u32], free: &mut Vec<u32>) -> u32 {
if b == 0 { return a; }
if a == 0 { return b; }
let [bl, br] = ch[b as usize];
if bl == 0 && br == 0 { free.push(b); return a; }
let [al, ar] = ch[a as usize];
let nl = ch_merge(al, bl, ch, ct, free);
let nr = ch_merge(ar, br, ch, ct, free);
ch[a as usize] = [nl, nr];
ct[a as usize] = if nl != 0 { ct[nl as usize] } else { 0 }
+ if nr != 0 { ct[nr as usize] } else { 0 };
free.push(b);
a
}
#[inline(always)]
fn ch_insert(root: u32, v: i32, ch: &mut [[u32; 2]], ct: &mut [u32], pool: &mut u32, free: &mut Vec<u32>) -> u32 {
const BITS: usize = 17;
let root = if root == 0 { ch_alloc(ch, ct, pool, free) } else { root };
let mut path = [0u32; BITS + 1];
path[0] = root;
let mut cur = root;
let mut is_new = false;
for d in 0..BITS {
let b = ((v >> (BITS - 1 - d)) & 1) as usize;
if ch[cur as usize][b] == 0 {
ch[cur as usize][b] = ch_alloc(ch, ct, pool, free);
is_new = true;
}
cur = ch[cur as usize][b];
path[d + 1] = cur;
}
if is_new { for &node in &path { ct[node as usize] += 1; } }
root
}
fn ch_collect(root: u32, ch: &[[u32; 2]], out: &mut Vec<i32>, stk: &mut Vec<(u32, i32, u32)>) {
if root == 0 { return; }
stk.push((root, 0, 17));
while let Some((s, sv, sb)) = stk.pop() {
let (mut node, mut val, mut bits) = (s, sv, sb);
loop {
if bits == 0 { out.push(val); break; }
bits -= 1;
let bit = bits as i32;
let [l, r] = ch[node as usize];
if l != 0 && r != 0 { stk.push((r, val | (1 << bit), bits)); node = l; }
else if l != 0 { node = l; }
else { val |= 1 << bit; node = r; }
}
}
}
impl Solution {
pub fn kth_smallest(par: Vec<i32>, vals: Vec<i32>, queries: Vec<Vec<i32>>) -> Vec<i32> {
let n = par.len();
let q = queries.len();
let mut tree: Vec<Vec<usize>> = vec![vec![]; n];
for i in 1..n { tree[par[i] as usize].push(i); }
let mut query_at: Vec<Vec<(u32, usize)>> = vec![vec![]; n];
for (i, qi) in queries.iter().enumerate() {
query_at[qi[0] as usize].push((qi[1] as u32, i));
}
let mut ans = vec![0i32; q];
let mut xp = vec![0i32; n];
xp[0] = vals[0];
// ch[i]=[left,right], ct[i]=count; node 0 = null sentinel.
// Peak live nodes <= 17*n (path nodes) + n (roots) = 18*n.
let max_nodes = 18 * n + 1024;
let mut ch: Vec<[u32; 2]> = vec![[0, 0]; max_nodes];
let mut ct: Vec<u32> = vec![0u32; max_nodes];
let mut pool: u32 = 1;
let mut free: Vec<u32> = Vec::with_capacity(4096);
let mut roots: Vec<u32> = vec![0u32; n];
let mut col_stk: Vec<(u32, i32, u32)> = Vec::with_capacity(512);
let mut col_buf: Vec<i32> = Vec::with_capacity(512);
let mut dfs: Vec<(usize, bool)> = vec![(0, false)];
while let Some((node, done)) = dfs.pop() {
if !done {
dfs.push((node, true));
for &c in &tree[node] {
xp[c] = xp[node] ^ vals[c];
dfs.push((c, false));
}
} else {
// small-to-large: take child with largest ct as base
let mut base = usize::MAX;
let mut bcnt = 0u32;
for &c in &tree[node] {
let r = roots[c];
if r != 0 && ct[r as usize] > bcnt { bcnt = ct[r as usize]; base = c; }
}
let mut root = if base != usize::MAX { roots[base] } else { 0 };
root = ch_insert(root, xp[node], &mut ch, &mut ct, &mut pool, &mut free);
for &c in &tree[node] {
if c == base { continue; }
let cr = roots[c];
if cr != 0 { root = ch_merge(root, cr, &mut ch, &mut ct, &mut free); }
}
if !query_at[node].is_empty() {
ch_collect(root, &ch, &mut col_buf, &mut col_stk);
let sz = col_buf.len();
for &(k, idx) in &query_at[node] {
ans[idx] = if k as usize > sz { -1 } else { col_buf[k as usize - 1] };
}
col_buf.clear();
}
roots[node] = root;
}
}
ans
}
}