$nodes = []; // [[metadata], parent_id, children_count, meta_length]
$current_id = null;
$state = 0; // 0: header children count, 1: header meta length, 2: meta
$nums = $input->numbers;
for ($i = 0; $i < $nums->count(); $i++) {
$num = $nums[$i];
switch ($state) {
// Start new node, register node and children count
case 0:
if ($current_id !== null) $nodes[$current_id][2]--;
$nodes[] = [[], $current_id, $num, 0];
$current_id = count($nodes) - 1;
$state = 1;
break;
// Register meta length
case 1:
$nodes[$current_id][3] = $num;
$state = $nodes[$current_id][2] ? 0 : 2;
break;
// Register meta, go to next children or to parent
case 2:
$nodes[$current_id][0] = (array) $nums->slice($i, $nodes[$current_id][3]);
$i += $nodes[$current_id][3] - 1;
$current_id = $nodes[$current_id][1];
if ($current_id === null) break 2; // End of tree
$state = $nodes[$current_id][2] ? 0 : 2;
break;
}
}
// ==================================================
// > PART 1
// ==================================================
$solution_1 = set($nodes)->column(0)->merge()->sum();
// ==================================================
// > PART 2
// ==================================================
for ($i = count($nodes) - 1; $i >= 0; $i--) {
$children = array_values(array_filter($nodes, fn ($node) => $node[1] === $i));
if (!$children) {
$nodes[$i][4] = array_sum($nodes[$i][0]);
continue;
}
$nodes[$i][4] = 0;
foreach ($nodes[$i][0] as $meta) {
if (isset($children[$meta - 1])) {
$nodes[$i][4] += $children[$meta - 1][4];
}
}
}
$solution_2 = $nodes[0][4];