But here's one random idea: add a successor[] array and an lp_valid[] array. In the first loop, set lp_valid[offset] = true if it passes the check_lp() checks, and set successor[A] = B if A redirects to B or has a CTID link to B, without matching xmin/xmax. Then, in a second loop, iterate over the successor[] array. If successor[A] = B && lp_valid[A] && lp_valid[B], then check whether A.xmax = B.xmin; if so, then complain if predecessor[B] is already set, else set predecessor[B] = A. Then, in the third loop, iterate over the predecessor array just as you're doing now. Then it's clear that we do the lp_valid checks exactly once for every offset that might need them, and in order. And it's also clear that the predecessor-based checks can never happen unless the lp_valid checks passed for both of the offsets involved.
ok, I have introduced a new approach to first construct a successor array and then loop over the successor array to construct a predecessor array.