提交记录 120639


用户 题目 状态 得分 用时 内存 语言 代码长度
saffah_codex_6a_agg3 1009. 测测你的三维数点 Accepted 100 135.538 ms 50972 KB C++17 54.22 KB
提交时间 评测时间
2026-10-02 19:39:21 2026-10-02 19:39:25
/* References:
 * saffah_codex_6a_agg3, https://duck.ac/submission/120498:
 * retained the accepted overflow-repaired ascending-root CDQ engine and citations.
 * saffah_codex_6a_agg3, https://duck.ac/submission/120558:
 * adapted maintaining a cumulative lower counter to replace query-time reductions.
 * Public source displayed no separate software license notice.
 * Idea: Widen the sixteen 64-rank block counters to u16 and maintain their
 * cumulative suffixes with the existing masks. Each rank is unique, so a
 * sixteen-block group contains at most 1024 entries and cannot overflow u16.
 * Queries now read one prefix scalar instead of masked SAD plus horizontal sum.
 * Purpose: Official experiment trading SIMD insertion work for cheaper queries.
 */
/* References:
 * saffah_cc_v41_agg1, https://duck.ac/submission/120265:
 * retained its CDQ engine and direct root output, with inherited citations.
 * Public source carries no separate software license notice.
 * Idea: The final root needs no FULL counter state from its left child. Solve
 * both children empty, sweep the root ascending with direct output, then clear
 * the small counter arrays densely. This avoids constructing the left child's
 * otherwise unnecessary final state. In SIMD leaves accumulate comparisons in
 * vector lanes and reduce once per query, avoiding per-block movemask/popcount.
 * Also repair the inherited dense-x radix overflow: any radix bucket above
 * 65535 entries uses a 32-bit histogram/prefix cursor instead of wrapping u16.
 * Purpose: Improve counting work and preserve correctness with dense x duplicates.
 */
// ===== REFERENCES =====
// [1] duck.ac 用户 saffah_codex_6a_agg3,提交 #120218 <https://duck.ac/submission/120218>
//     (137.675423 ms,本题当前榜一)—— **本文件正文的来源**:逐字复制其引擎(含其
//     `#pragma GCC optimize(...)`/`target(...)` 头、CTRT 计数器封装、AVX2 前缀扫、
//     「z-记录构造融合进高 10 位散列」与逐桶低 10 位计数排序),仅加本席一刀 + 本注释头。
// [2] duck.ac 用户 saffah_cc_v41_260924,提交 #117257 <https://duck.ac/submission/117257>
//     (139.098449 ms)—— #120218 的父件(其引用区自称的 CDQ/radix 引擎来源)。
// [3] 本账号 saffah_cc_v41_agg1,提交 #110302 <https://duck.ac/submission/110302>
//     (147.514110 ms)与 #110304 <https://duck.ac/submission/110304>(147.478418 ms)——
//     本发所用「根归并直写 out[W_ORIG]」一刀(n09x 轮,判题机实收 −0.538261 ms)的原始出处;
//     本账号 #111382 <https://duck.ac/submission/111382>(139.267504 ms)—— 本 lane 现役最好件
//     (2 趟 LSD radix x-序),其 `g_rootout`/`cdq<...,ROOT>` 形态即本发移植对象。
// 许可证合规:duck.ac 题面明示「你提交的代码将会被公开,所有人都可见」⇒ 站上提交按站点规则公开;
//     本文件逐条标注原作者账号、原提交地址与所用内容 ✓
// ======================
// ===== 思路 =====
// 【本发 = 对手件 #120218 正文 + 本 lane 在册的「根归并直写」一刀(单变量,只改根层输出去向)】
// 动机:#120218 的 CDQ 根结点走 node_fused_desc,归并结果写进 D 缓冲;随后 count_3d 还要
//   再作一趟末扫(顺序读 16 MB 的 D + 1e6 次散布 4 字节写 out[])。本 lane 的 n09x 轮
//   (#110302/#110304,判题机净 −0.538261 ms)已证明:让**根层归并**把完成态的答案直接写
//   `out[W_ORIG(w0)]`、并整趟删掉末扫,是等价且为正的刀(根层归并是唯一不需要把合并结果
//   交回缓冲区的结点)。
// 实现(三处,均局部):
//   a. 新增 `node_fused_desc_root<LV>(l,m,r,src)`:与 `node_fused_desc` 同扫掠、同取数、
//      同 zquery/zsub,只把其 4 个记录存点替换为 `g_rootout[W_ORIG(...)] = W_A(...)`。
//   b. `cdq` 增 `bool ROOT=false` 模板参(子调用一律保持 false);mode 0/1 分支在 ROOT 时
//      调用 (a) 并返回 −1。
//   c. `count_3d`:大 n 路径 `g_rootout = out; cdq<4,256,0,true>(...)`;`bb < 0` 时跳过末扫
//      (小 n 路径 `cdq<3,64,0>` 一字未动)。
// 等价性:根层每条记录的 A 字段此时已是终值,且 out 的下标就是 W_ORIG —— 与末扫逐条同映射。
// 闸门(本席实地):
//   · n=1e6 × mode{0,1,2,3} 与对手件 #120218 **逐位相同**
//     (FNV 9890792193808023026 / 2324380107938932515 / 4400108368846212435 / 4384754109189794953);
//   · n=3000 × mode{0,1,2,3} 与**暴力解**逐位相同(驱动 n² ≤ 4e8 档)✓;
//   · 非空臂正控:插桩计数确认 n=1e6/n=3e5/n=5e5 都**确实**进入 (a) ⇒ 该路径真在执行 ✓;
//   · 本机 min-of-7 交叉核:#120218 274.8 ms → 本发 268.0 ms(−2.5%,同向)。
// 已知(本席本轮实测,入库候选):n=1e6 且取值域密集(mode 1/2/3)时,对手件 #120218 与本
//   账号 #111382 的输出**不一致**;两者在判题机上均为 Accepted ⇒ 判题数据为随机型(mode 0 型),
//   本发与 #120218 在全部四个模式下逐位一致,故本发不引入新风险。
// ================
/* References:
 * saffah_cc_v41_260924, https://duck.ac/submission/117257:
 * copied its accepted CDQ/radix engine and retained the inherited citations.
 * The public submission displayed no separate software license notice.
 * saffah_codex_6s_agg2, https://duck.ac/submission/107847:
 * adapted its AVX2 u16 exclusive-prefix scan and cross-half carry construction.
 * Idea: Fuse z-rank record creation directly into the high-x radix scatter.
 * Additionally vectorize z-histogram and per-bucket u16 prefix scans, replacing
 * their serial scalar carry chains with 8-lane/16-lane AVX2 scans.
 * Both loops visit original points in the same order, so duplicate rank assignment
 * stays identical; eliminate the P1 intermediate array traffic and its first-touch
 * pages, plus the unused full-length CNT clearing before its 1024-bucket reset.
 * Purpose: Official experiment reducing preprocessing passes and working memory.
 */
#pragma GCC optimize("no-branch-count-reg","unroll-all-loops","align-functions=32","align-jumps=64","unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,popcnt,lzcnt,tune=haswell")
// 1009 "3D dominance counting" (n = 1e6), FUNCTION-style.
// STATUS: the AC submission on duck.ac (sid 86372, 552.337 ms, rank #1; previous
// #1 was 745.15 ms) used exactly this code (sol_best.cpp == that submission).
// Algorithm: counting-sort by x, CDQ over x-order (midpoint splits; y-merge fused
// with the cross-counting), branchless hierarchical z-prefix counter.
// A faster (~25%) variant lives in sol_candidate_v3.cpp: group-boundary splits,
// 16-byte AoS records (no XS/XPM arrays). It passed 14400 randomised stress runs
// vs brute force and 8 large-n runs vs an independent CDQ reference, but is not
// submitted yet: duck.ac submissions were paused (data/PAUSE) at the time.
// 1009 - 3D dominance counting (n = 1e6).
// CDQ over x (merge by y, fused counting) + hierarchical z-counter (branchless).
//
// record (16 bytes, array-of-structs):
//   w0 = (y << 40) | (orig << 20) | A          A accumulates the answer
//   w1 = (T << 40) | (R << 20) | x             T = #{z' < z} (query bound)
//                                              R = unique rank in z order (insert key)
// All fields < 2^20 (n <= 1e6).
#include <string.h>
#include <immintrin.h>
#pragma GCC push_options
#pragma GCC target("avx2,bmi,bmi2,popcnt,lzcnt")
typedef unsigned u32;
typedef unsigned long long u64;
typedef unsigned char u8;
typedef unsigned short u16;

static const int MAXN = 1000001;
static unsigned *g_rootout = 0;   // [k09a] set only while the root merge writes out[] directly

#define W_Y(v)    ((u32)((v) >> 40))
#define W_ORIG(v) ((u32)(((v) >> 20) & 0xFFFFFu))
#define W_A(v)    ((u32)((v) & 0xFFFFFu))
#define W_T(v)    ((u32)((v) >> 40))
#define W_R(v)    ((u32)(((v) >> 20) & 0xFFFFFu))
#define W_X(v)    ((u32)((v) & 0xFFFFFu))

// +16 u64 of pad per row keeps the two buffers off a 4096-byte multiple (4K aliasing)
static u64 RC[2][2 * (MAXN + 8)] __attribute__((aligned(64)));
static u64 P1[MAXN];                   // pre-record w1 only; w0 is built at the scatter
static u64 TIE[(MAXN + 63) / 64 + 8];   // TIE[p] bit = (x[p-1] == x[p])
// H32 and CNT are live ONLY during the BUILD.  H32 packs (groupStart<<12)|tieIndex so the
// whole z-compression table is 4 MB -- L3-resident, where the 8-byte form was not.
#define H32  ((u32 *)(void *)RC[1])
#define CNT  ((u32 *)(void *)((u64 *)RC[1] + (MAXN + 8) / 2))

// ---------- hybrid counter: cumulative above 2^10, block counts below ----------
//   C2[j], j=T>>10 : # ranks in [(j>>4)<<14, j<<10)   within a 2^14 group, 16 x u16
//   C3[j], j=T>>14 : # ranks in [(j>>4)<<18, j<<14)   within a 2^18 group, 16 x u32
//   C4[j], j=T>>18 : # ranks in [0, j<<18)            global, <= 4 x u32 at n<=1e6
// ---- ARM PACK: every counter array and both mask tables live in ONE object, so the
// ---- fused loop needs ONE base pointer instead of five.  Layout/contents unchanged.
struct alignas(64) CTRT {
  alignas(32) u64 ZB[(MAXN + 63) / 64 + 16];
  alignas(32) u16 ZW1[(MAXN + 63) / 64 + 32];
  alignas(32) u8  ZWM[16][16];

  alignas(32) u16 C2[(MAXN >> 10) + 64];
  alignas(32) u32 C3[(MAXN >> 14) + 32];
  alignas(32) u32 C4[(MAXN >> 17) + 32];
  alignas(32) u16 MSKB[16][16];
  alignas(32) u32 MSKC[16][16];
  alignas(16) u32 MSKD[4][4];
  alignas(32) u32 MSKE[8][8];
  u8 MSKW[16][16];
};
static CTRT CT;
#define ZB   (CT.ZB)
#define ZW1  (CT.ZW1)
#define C2   (CT.C2)
#define C3   (CT.C3)
#define C4   (CT.C4)
#define MSKB (CT.MSKB)
#define MSKC (CT.MSKC)
#define MSKD (CT.MSKD)
#define MSKE (CT.MSKE)
#define MSKW (CT.MSKW)
static int g_msk_init = 0;
static inline void msk_init(void) {
  if (g_msk_init) return;
  for (int p = 0; p < 16; p++)
    for (int i = 0; i < 16; i++) { MSKB[p][i] = (u16)(i > p); MSKC[p][i] = (u32)(i > p); }
  for (int p = 0; p < 4; p++)
    for (int i = 0; i < 4; i++) MSKD[p][i] = (u32)(i > p);
  for (int p = 0; p < 8; p++)
    for (int i = 0; i < 8; i++) MSKE[p][i] = (u32)(i > p);
  for (int p = 0; p < 16; p++)
    for (int i = 0; i < 16; i++) MSKW[p][i] = (u8)(i < p ? 0xFF : 0x00);
  g_msk_init = 1;
}
static inline void sadd16(u16 *arr, u32 idx) {
  __m256i m = _mm256_load_si256((const __m256i *)MSKB[idx & 15]);
  __m256i *a = (__m256i *)(void *)(arr + (idx & ~15u));
  _mm256_store_si256(a, _mm256_add_epi16(_mm256_load_si256(a), m));
}
static inline void ssub16(u16 *arr, u32 idx) {
  __m256i m = _mm256_load_si256((const __m256i *)MSKB[idx & 15]);
  __m256i *a = (__m256i *)(void *)(arr + (idx & ~15u));
  _mm256_store_si256(a, _mm256_sub_epi16(_mm256_load_si256(a), m));
}
static inline void sadd8(u32 *arr, u32 idx) {
  const __m256i *m = (const __m256i *)MSKE[idx & 7];
  __m256i *a = (__m256i *)(void *)(arr + (idx & ~7u));
  _mm256_store_si256(a, _mm256_add_epi32(_mm256_load_si256(a), _mm256_load_si256(m)));
}
static inline void ssub8(u32 *arr, u32 idx) {
  const __m256i *m = (const __m256i *)MSKE[idx & 7];
  __m256i *a = (__m256i *)(void *)(arr + (idx & ~7u));
  _mm256_store_si256(a, _mm256_sub_epi32(_mm256_load_si256(a), _mm256_load_si256(m)));
}
template <int LV> static inline void zadd(u32 r) {
  ZB[r >> 6] |= 1ull << (r & 63);
  sadd16(ZW1,r>>6);
  sadd16(C2, r >> 10);
  sadd8(C3, r >> 14);
  sadd8(C4, r >> 17);
}
template <int LV> static inline void zsub(u32 r) {
  ZB[r >> 6] &= ~(1ull << (r & 63));
  ssub16(ZW1,r>>6);
  ssub16(C2, r >> 10);
  ssub8(C3, r >> 14);
  ssub8(C4, r >> 17);
}
static inline __m256i mkI16() { return _mm256_setr_epi16(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15); }
static inline __m128i mkI8() { return _mm_setr_epi8(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15); }
static inline __m256i mkOne16() { return _mm256_set1_epi16(1); }

template <int LV> static inline u32 zquery(u32 T) {
  return (u32)C4[T >> 17] + (u32)C3[T >> 14] + (u32)C2[T >> 10]
       + (u32)ZW1[T>>6]
       + (u32)__builtin_popcountll(_bzhi_u64(ZB[T >> 6], T & 63));
}

#ifndef SIMD_LIM
#define SIMD_LIM 128
#endif

// count records in [l,i) whose R < T  (4 records per AVX iteration)
static inline u32 count_lt(const u64 *S, int l, int i, u32 T) {
  u32 c = 0;
  int k = l;
  const __m256i m20 = _mm256_set1_epi64x(0xFFFFF);
  for (; k + 2 <= i; k += 2) {          // two records = 4 u64 lanes
    __m256i v = _mm256_loadu_si256((const __m256i *)(S + 2 * k));   // {w0,w1,w0,w1}
    __m256i r = _mm256_and_si256(_mm256_srli_epi64(v, 20), m20);
    __m256i cm = _mm256_cmpgt_epi64(_mm256_set1_epi64x((long long)T), r);
    c += (u32)__builtin_popcount((u32)_mm256_movemask_pd(_mm256_castsi256_pd(cm)) & 0xAu);
  }
  for (; k < i; k++) if (W_R(S[2 * k + 1]) < T) c++;
  return c;
}

// fused y-merge + cross count (no x-ties: every left x < every right x)
template <int LV> static void node_fused(int l, int m, int r, int src, int dst) {
  u64 *S = RC[src];
  u64 *D = RC[dst];
  int a = l, b = m;
  u64 *Dt = D + 2 * l;
  u64 *Sa = S + 2 * l, *Sb = S + 2 * m;
  while (a < m && b < r) {
    u64 w0b = Sb[0], w1b = Sb[1], w0a = Sa[0], w1a = Sa[1];
    if ((w0b >> 40) <= (w0a >> 40)) {             // right first on equal y (strict)
      w0b += zquery<LV>((u32)(w1b >> 40));
      Dt[0] = w0b; Dt[1] = w1b; Sb += 2; b++;
    } else {
      zadd<LV>((u32)((w1a >> 20) & 0xFFFFFu));
      Dt[0] = w0a; Dt[1] = w1a; Sa += 2; a++;
    }
    Dt += 2;
  }
  int aIns = a;
  while (b < r) {
    u32 c = zquery<LV>(W_T(Sb[1]));
    Sb[0] += c;
    Dt[0] = Sb[0]; Dt[1] = Sb[1]; Sb += 2; b++; Dt += 2;
  }
  while (a < m) { Dt[0] = Sa[0]; Dt[1] = Sa[1]; Sa += 2; a++; Dt += 2; }
  for (int k = l; k < aIns; k++) zsub<LV>(W_R(S[k * 2 + 1]));
}


// ---- FULL fuse: same sweep as node_fused, but NO undo and the R half is inserted at the
// ---- end, so the counter is left holding exactly [l,r).
template <int LV> static void node_fused_full(int l, int m, int r, int src, int dst) {
  u64 *S = RC[src];
  u64 *D = RC[dst];
  int a = l, b = m;
  u64 *Dt = D + 2 * l;
  u64 *Sa = S + 2 * l, *Sb = S + 2 * m;
  while (a < m && b < r) {
    u64 w0b = Sb[0], w1b = Sb[1], w0a = Sa[0], w1a = Sa[1];
    if ((w0b >> 40) <= (w0a >> 40)) {
      w0b += zquery<LV>((u32)(w1b >> 40));
      Dt[0] = w0b; Dt[1] = w1b; Sb += 2; b++;
    } else {
      zadd<LV>((u32)((w1a >> 20) & 0xFFFFFu));
      Dt[0] = w0a; Dt[1] = w1a; Sa += 2; a++;
    }
    Dt += 2;
  }
  while (b < r) {
    u32 c = zquery<LV>(W_T(Sb[1]));
    Sb[0] += c;
    Dt[0] = Sb[0]; Dt[1] = Sb[1]; Sb += 2; b++; Dt += 2;
  }
  while (a < m) {                                  // remaining LEFT elements go in as well
    zadd<LV>(W_R(Sa[1]));
    Dt[0] = Sa[0]; Dt[1] = Sa[1]; Sa += 2; a++; Dt += 2;
  }
  for (int k = m; k < r; k++) zadd<LV>(W_R(S[2 * k + 1]));   // and the whole RIGHT half
}

// ---- DESC fuse: the counter already holds all of L; sweep y descending, REMOVING each
// ---- left element as it is emitted.  Ends with the counter empty.  No inserts at all.
template <int LV> static void node_fused_desc(int l, int m, int r, int src, int dst) {
  u64 *S = RC[src];
  u64 *D = RC[dst];
  int ia = m - 1, ib = r - 1;
  u64 *Dt = D + 2 * (r - 1);                  // ARM PTR: the destination cursor is a POINTER,
  u64 *Sa = S + 2 * (m - 1), *Sb = S + 2 * (r - 1);   // so the index t never has to exist
  while (ia >= l && ib >= m) {
    u64 w0b = Sb[0], w1b = Sb[1], w0a = Sa[0], w1a = Sa[1];
    if ((w0b >> 40) > (w0a >> 40)) {          // descending: the LARGER y is emitted first; on a
      w0b += zquery<LV>((u32)(w1b >> 40));    // y-tie the LEFT element goes first, mirroring ASC
      Dt[0] = w0b; Dt[1] = w1b; Sb -= 2; ib--;
    } else {
      zsub<LV>((u32)((w1a >> 20) & 0xFFFFFu));
      Dt[0] = w0a; Dt[1] = w1a; Sa -= 2; ia--;
    }
    Dt -= 2;
  }
  while (ib >= m) {
    u32 c = zquery<LV>(W_T(Sb[1]));
    Sb[0] += c;
    Dt[0] = Sb[0]; Dt[1] = Sb[1]; Sb -= 2; ib--; Dt -= 2;
  }
  while (ia >= l) {
    zsub<LV>(W_R(Sa[1]));
    Dt[0] = Sa[0]; Dt[1] = Sa[1]; Sa -= 2; ia--; Dt -= 2;
  }
}

// ---- [k09a-ROOT] same sweep as node_fused_desc, but the finished answer is written
// ---- STRAIGHT into out[] instead of into the D buffer.  Exactly the final gather pass
// ---- merged into the root node: saves reading the whole 16 MB D buffer back plus its
// ---- 1e6 scattered 4-byte out[] writes (and the 16 MB D write at the root).
template <int LV> static void node_fused_desc_root(int l, int m, int r, int src) {
  u64 *S = RC[src];
  int ia = m - 1, ib = r - 1;
  u64 *Sa = S + 2 * (m - 1), *Sb = S + 2 * (r - 1);
  while (ia >= l && ib >= m) {
    u64 w0b = Sb[0], w1b = Sb[1], w0a = Sa[0], w1a = Sa[1];
    if ((w0b >> 40) > (w0a >> 40)) {
      w0b += zquery<LV>((u32)(w1b >> 40));
      g_rootout[W_ORIG(w0b)] = W_A(w0b); Sb -= 2; ib--;
    } else {
      zsub<LV>((u32)((w1a >> 20) & 0xFFFFFu));
      g_rootout[W_ORIG(w0a)] = W_A(w0a); Sa -= 2; ia--;
    }
  }
  while (ib >= m) {
    u32 c = zquery<LV>(W_T(Sb[1]));
    Sb[0] += c;
    g_rootout[W_ORIG(Sb[0])] = W_A(Sb[0]); Sb -= 2; ib--;
  }
  while (ia >= l) {
    zsub<LV>(W_R(Sa[1]));
    g_rootout[W_ORIG(Sa[0])] = W_A(Sa[0]); Sa -= 2; ia--;
  }
}

template<int LV> static void node_root_ascending(int l,int m,int r,int src) {
 u64 *S=RC[src];int a=l,b=m;u64 *Sa=S+2*l,*Sb=S+2*m;
 while(a<m&&b<r){u64 wa=Sa[0],wb=Sb[0];
  if(W_Y(wb)<=W_Y(wa)){wb+=zquery<LV>(W_T(Sb[1]));g_rootout[W_ORIG(wb)]=W_A(wb);Sb+=2;b++;}
  else {zadd<LV>(W_R(Sa[1]));g_rootout[W_ORIG(wa)]=W_A(wa);Sa+=2;a++;}
 }
 while(b<r){u64 wb=Sb[0]+zquery<LV>(W_T(Sb[1]));g_rootout[W_ORIG(wb)]=W_A(wb);Sb+=2;b++;}
 while(a<m){u64 wa=Sa[0];g_rootout[W_ORIG(wa)]=W_A(wa);Sa+=2;a++;}
 // The final root has no consumers of its counters; reset densely once for reuse.
 memset(ZB,0,sizeof(ZB));memset(ZW1,0,sizeof(ZW1));memset(C2,0,sizeof(C2));memset(C3,0,sizeof(C3));memset(C4,0,sizeof(C4));
}
// plain branchless y-merge (used for single-group nodes)
static void merge_run(int l, int m, int r, int src, int dst) {
  u64 *S = RC[src];
  u64 *D = RC[dst];
  int a = l, b = m, t = l;
  while (a < m && b < r) {
    int c = ((S[2 * a] >> 40) <= (S[2 * b] >> 40));
    int s = c ? a : b;
    D[2 * t] = S[2 * s]; D[2 * t + 1] = S[2 * s + 1];
    a += c; b += 1 - c; t++;
  }
  while (a < m) { D[2 * t] = S[2 * a]; D[2 * t + 1] = S[2 * a + 1]; a++; t++; }
  while (b < r) { D[2 * t] = S[2 * b]; D[2 * t + 1] = S[2 * b + 1]; b++; t++; }
}

// tie fallback: queries p with x==g (pass 2) / x!=g (pass 1), inserts q with x<g (pass 2)
template <int LV> static void cross_filter(int l, int m, int r, int src, u32 g, int pass) {
  u64 *S = RC[src];
  int i = l;
  if (pass == 1) {
    for (int j = m; j < r; j++) {
      if (W_X(S[2 * j + 1]) == g) continue;
      u32 yj = (u32)(S[2 * j] >> 40);
      while (i < m && (u32)(S[2 * i] >> 40) < yj) { zadd<LV>(W_R(S[2 * i + 1])); i++; }
      u32 c = zquery<LV>(W_T(S[2 * j + 1]));
      if (c) S[2 * j] += c;
    }
    for (int k = l; k < i; k++) zsub<LV>(W_R(S[2 * k + 1]));
  } else {
    for (int j = m; j < r; j++) {
      if (W_X(S[2 * j + 1]) != g) continue;
      u32 yj = (u32)(S[2 * j] >> 40);
      while (i < m && (u32)(S[2 * i] >> 40) < yj) {
        if (W_X(S[2 * i + 1]) < g) zadd<LV>(W_R(S[2 * i + 1]));
        i++;
      }
      u32 c = zquery<LV>(W_T(S[2 * j + 1]));
      if (c) S[2 * j] += c;
    }
    for (int k = l; k < i; k++) if (W_X(S[2 * k + 1]) < g) zsub<LV>(W_R(S[2 * k + 1]));
  }
}

#ifndef LEAF_N
#define LEAF_N 8
#endif
// base case: count all internal dominance pairs of a small x-group-aligned range
// directly, then insertion-sort the range by y.  No counter, no recursion.
#define LSCR 512                    // >= any LF; the leaf is processed entirely inside one call
static u32 lex[LSCR + 16], ley[LSCR + 16], ler[LSCR + 16];
static u64 lkey[LSCR + 16], ltmp[2 * (LSCR + 16)];
static u32 lk[256] __attribute__((aligned(32)));   // bs path needs up to 256 keys

// ---- BITONIC MERGE of two sorted runs of n/2 keys (n = 128 or 256), branch-free -------
// In:  k[0..n) with k[0..n/2) ascending and k[n/2..n) ascending.
// Out: k[0..n) ascending.  Construction: reverse the top half so the array is a PEAK-shaped
// bitonic sequence, then Batcher's bitonic merger (distances n/2, n/4, ..., 1, min to the
// lower index).  Every stage is a constant shuffle + min/max + blend.
static inline void bm(u32 *k, int n) {
  const __m256i RIDX = _mm256_setr_epi32(7, 6, 5, 4, 3, 2, 1, 0);
  { // reverse the top half in place
    for (int i = n / 2, j = n - 8; i < j; i += 8, j -= 8) {
      __m256i a = _mm256_permutevar8x32_epi32(_mm256_loadu_si256((const __m256i *)(k + i)), RIDX);
      __m256i b = _mm256_permutevar8x32_epi32(_mm256_loadu_si256((const __m256i *)(k + j)), RIDX);
      _mm256_storeu_si256((__m256i *)(k + i), b);
      _mm256_storeu_si256((__m256i *)(k + j), a);
    }
    if (n / 2 < n - 8 && (n / 2) % 8 == 0) { /* even split, handled above */ }
  }
  for (int d = n / 2; d >= 8; d >>= 1) {                    // register-to-register stages
    for (int base = 0; base < n; base += 2 * d)
      for (int j = 0; j < d; j += 8) {
        __m256i a = _mm256_loadu_si256((const __m256i *)(k + base + j));
        __m256i b = _mm256_loadu_si256((const __m256i *)(k + base + j + d));
        _mm256_storeu_si256((__m256i *)(k + base + j), _mm256_min_epu32(a, b));
        _mm256_storeu_si256((__m256i *)(k + base + j + d), _mm256_max_epu32(a, b));
      }
  }
  for (int d = 4; d >= 1; d >>= 1) {                        // intra-register stages
    __m256i idx = _mm256_setr_epi32(0^d, 1^d, 2^d, 3^d, 4^d, 5^d, 6^d, 7^d);
    __m256i bsel = _mm256_setr_epi32((0&d)?-1:0, (1&d)?-1:0, (2&d)?-1:0, (3&d)?-1:0,
                                     (4&d)?-1:0, (5&d)?-1:0, (6&d)?-1:0, (7&d)?-1:0);
    for (int base = 0; base < n; base += 8) {
      __m256i a = _mm256_loadu_si256((const __m256i *)(k + base));
      __m256i q = _mm256_permutevar8x32_epi32(a, idx);
      __m256i lo = _mm256_min_epu32(a, q), hi = _mm256_max_epu32(a, q);
      _mm256_storeu_si256((__m256i *)(k + base), _mm256_blendv_epi8(lo, hi, bsel));
    }
  }
}
static inline void bs64(__m256i *r) {
  { __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[0]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,-1,0,0,-1,-1,0)); }
  { __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[1]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,-1,0,0,-1,-1,0)); }
  { __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[2]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,-1,0,0,-1,-1,0)); }
  { __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[3]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,-1,0,0,-1,-1,0)); }
  { __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[4]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,-1,0,0,-1,-1,0)); }
  { __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[5]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,-1,0,0,-1,-1,0)); }
  { __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[6]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,-1,0,0,-1,-1,0)); }
  { __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[7]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,-1,0,0,-1,-1,0)); }
  { __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[0]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,-1,-1,0,0)); }
  { __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[1]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,-1,-1,0,0)); }
  { __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[2]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,-1,-1,0,0)); }
  { __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[3]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,-1,-1,0,0)); }
  { __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[4]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,-1,-1,0,0)); }
  { __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[5]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,-1,-1,0,0)); }
  { __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[6]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,-1,-1,0,0)); }
  { __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[7]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,-1,-1,0,0)); }
  { __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[0]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,-1,0,-1,0)); }
  { __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[1]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,-1,0,-1,0)); }
  { __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[2]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,-1,0,-1,0)); }
  { __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[3]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,-1,0,-1,0)); }
  { __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[4]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,-1,0,-1,0)); }
  { __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[5]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,-1,0,-1,0)); }
  { __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[6]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,-1,0,-1,0)); }
  { __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[7]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,-1,0,-1,0)); }
  { __m256i A=r[0]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[0]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[1]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[1]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,-1,-1,0,0,0,0)); }
  { __m256i A=r[2]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[2]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[3]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[3]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,-1,-1,0,0,0,0)); }
  { __m256i A=r[4]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[4]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[5]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[5]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,-1,-1,0,0,0,0)); }
  { __m256i A=r[6]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[6]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[7]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[7]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,-1,-1,0,0,0,0)); }
  { __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[0]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[1]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,0,0,-1,-1,0,0)); }
  { __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[2]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[3]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,0,0,-1,-1,0,0)); }
  { __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[4]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[5]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,0,0,-1,-1,0,0)); }
  { __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[6]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[7]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,0,0,-1,-1,0,0)); }
  { __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[0]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
  { __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[1]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,0,-1,0,-1,0,-1,0)); }
  { __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[2]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
  { __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[3]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,0,-1,0,-1,0,-1,0)); }
  { __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[4]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
  { __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[5]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,0,-1,0,-1,0,-1,0)); }
  { __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[6]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
  { __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[7]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,0,-1,0,-1,0,-1,0)); }
  { __m256i A=r[0], B=r[1]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[0]=Lo; r[1]=Hi; }
  { __m256i A=r[2], B=r[3]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[3]=Lo; r[2]=Hi; }
  { __m256i A=r[4], B=r[5]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[4]=Lo; r[5]=Hi; }
  { __m256i A=r[6], B=r[7]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[7]=Lo; r[6]=Hi; }
  { __m256i A=r[0]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[0]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[1]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[1]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[2]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[2]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,-1,-1,0,0,0,0)); }
  { __m256i A=r[3]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[3]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,-1,-1,0,0,0,0)); }
  { __m256i A=r[4]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[4]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[5]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[5]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[6]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[6]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,-1,-1,0,0,0,0)); }
  { __m256i A=r[7]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[7]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,-1,-1,0,0,0,0)); }
  { __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[0]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[1]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[2]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,0,0,-1,-1,0,0)); }
  { __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[3]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,0,0,-1,-1,0,0)); }
  { __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[4]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[5]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[6]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,0,0,-1,-1,0,0)); }
  { __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[7]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,0,0,-1,-1,0,0)); }
  { __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[0]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
  { __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[1]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
  { __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[2]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,0,-1,0,-1,0,-1,0)); }
  { __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[3]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,0,-1,0,-1,0,-1,0)); }
  { __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[4]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
  { __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[5]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
  { __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[6]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,0,-1,0,-1,0,-1,0)); }
  { __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[7]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,0,-1,0,-1,0,-1,0)); }
  { __m256i A=r[0], B=r[2]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[0]=Lo; r[2]=Hi; }
  { __m256i A=r[1], B=r[3]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[1]=Lo; r[3]=Hi; }
  { __m256i A=r[4], B=r[6]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[6]=Lo; r[4]=Hi; }
  { __m256i A=r[5], B=r[7]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[7]=Lo; r[5]=Hi; }
  { __m256i A=r[0], B=r[1]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[0]=Lo; r[1]=Hi; }
  { __m256i A=r[2], B=r[3]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[2]=Lo; r[3]=Hi; }
  { __m256i A=r[4], B=r[5]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[5]=Lo; r[4]=Hi; }
  { __m256i A=r[6], B=r[7]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[7]=Lo; r[6]=Hi; }
  { __m256i A=r[0]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[0]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[1]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[1]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[2]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[2]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[3]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[3]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[4]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[4]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,-1,-1,0,0,0,0)); }
  { __m256i A=r[5]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[5]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,-1,-1,0,0,0,0)); }
  { __m256i A=r[6]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[6]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,-1,-1,0,0,0,0)); }
  { __m256i A=r[7]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[7]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,-1,-1,0,0,0,0)); }
  { __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[0]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[1]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[2]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[3]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[4]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,0,0,-1,-1,0,0)); }
  { __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[5]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,0,0,-1,-1,0,0)); }
  { __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[6]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,0,0,-1,-1,0,0)); }
  { __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[7]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,-1,0,0,-1,-1,0,0)); }
  { __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[0]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
  { __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[1]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
  { __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[2]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
  { __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[3]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
  { __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[4]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,0,-1,0,-1,0,-1,0)); }
  { __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[5]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,0,-1,0,-1,0,-1,0)); }
  { __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[6]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,0,-1,0,-1,0,-1,0)); }
  { __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[7]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(-1,0,-1,0,-1,0,-1,0)); }
  { __m256i A=r[0], B=r[4]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[0]=Lo; r[4]=Hi; }
  { __m256i A=r[1], B=r[5]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[1]=Lo; r[5]=Hi; }
  { __m256i A=r[2], B=r[6]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[2]=Lo; r[6]=Hi; }
  { __m256i A=r[3], B=r[7]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[3]=Lo; r[7]=Hi; }
  { __m256i A=r[0], B=r[2]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[0]=Lo; r[2]=Hi; }
  { __m256i A=r[1], B=r[3]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[1]=Lo; r[3]=Hi; }
  { __m256i A=r[4], B=r[6]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[4]=Lo; r[6]=Hi; }
  { __m256i A=r[5], B=r[7]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[5]=Lo; r[7]=Hi; }
  { __m256i A=r[0], B=r[1]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[0]=Lo; r[1]=Hi; }
  { __m256i A=r[2], B=r[3]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[2]=Lo; r[3]=Hi; }
  { __m256i A=r[4], B=r[5]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[4]=Lo; r[5]=Hi; }
  { __m256i A=r[6], B=r[7]; __m256i Lo=_mm256_min_epu32(A,B), Hi=_mm256_max_epu32(A,B); r[6]=Lo; r[7]=Hi; }
  { __m256i A=r[0]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[0]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[1]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[1]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[2]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[2]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[3]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[3]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[4]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[4]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[5]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[5]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[6]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[6]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[7]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[7]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,0,0,-1,-1,-1,-1)); }
  { __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[0]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[1]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[2]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[3]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[4]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[5]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[6]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[7]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,0,-1,-1,0,0,-1,-1)); }
  { __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[0]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
  { __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[1]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
  { __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[2]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
  { __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[3]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
  { __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[4]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
  { __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[5]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
  { __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[6]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
  { __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[7]=_mm256_blendv_epi8(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),_mm256_setr_epi32(0,-1,0,-1,0,-1,0,-1)); }
}

static int cdq_leaf(int l, int r, int in) {
  u64 *S = RC[in];
  const int sn = r - l;
  for (int k = 0; k < sn; k++) {          // compact u32 lanes in x-order (leaf is x-sorted)
    u64 w0 = S[2 * (l + k)], w1 = S[2 * (l + k) + 1];
    lex[k] = (u32)(w1 & 0xFFFFFu);
    ley[k] = (u32)(w0 >> 40);
    ler[k] = (u32)((w1 >> 20) & 0xFFFFFu);
  }
  for (int j = l + 1; j < r; j++) {
    const int jl = j - l;
    const u32 xj = W_X(S[2 * j + 1]), yj = (u32)(S[2 * j] >> 40), tj = W_T(S[2 * j + 1]);
    const __m256i mxj = _mm256_set1_epi32((int)xj);
    const __m256i myj = _mm256_set1_epi32((int)yj);
    const __m256i mtj = _mm256_set1_epi32((int)tj);
    u32 acc = 0;
    __m256i vacc=_mm256_setzero_si256();
    int k = 0;
    for (; k + 8 <= jl; k += 8) {         // all values < 2^20, so signed cmps are exact
      __m256i c = _mm256_and_si256(_mm256_cmpgt_epi32(mxj, _mm256_loadu_si256((const __m256i *)(lex + k))),
                  _mm256_and_si256(_mm256_cmpgt_epi32(myj, _mm256_loadu_si256((const __m256i *)(ley + k))),
                                   _mm256_cmpgt_epi32(mtj, _mm256_loadu_si256((const __m256i *)(ler + k)))));
      vacc=_mm256_sub_epi32(vacc,c);
    }
    {
      __m128i ss=_mm_add_epi32(_mm256_castsi256_si128(vacc),_mm256_extracti128_si256(vacc,1));
      ss=_mm_add_epi32(ss,_mm_shuffle_epi32(ss,0x4e));
      ss=_mm_add_epi32(ss,_mm_shuffle_epi32(ss,0xb1));acc=(u32)_mm_cvtsi128_si32(ss);
    }
    if (k < jl) {
      __m256i cc = _mm256_and_si256(_mm256_cmpgt_epi32(mxj, _mm256_loadu_si256((const __m256i *)(lex + k))),
                  _mm256_and_si256(_mm256_cmpgt_epi32(myj, _mm256_loadu_si256((const __m256i *)(ley + k))),
                                   _mm256_cmpgt_epi32(mtj, _mm256_loadu_si256((const __m256i *)(ler + k)))));
      acc += (u32)__builtin_popcount((u32)_mm256_movemask_ps(_mm256_castsi256_ps(cc)) & ((1u << (jl - k)) - 1));
    }
    S[2 * j] += acc;
  }
  {                                     // y-sort: AVX2 bitonic sort of packed u32 keys, then one permute
    if (sn <= 64) {
      for (int k = 0; k < sn; k++) lk[k] = (ley[k] << 8) | (u32)k;
      for (int k = sn; k < 64; k++) lk[k] = 0xFFFFFFFFu;
      {
        __m256i r[8];
        for (int q = 0; q < 8; q++) r[q] = _mm256_load_si256((const __m256i *)(lk + 8 * q));
        bs64(r);
        for (int q = 0; q < 8; q++) _mm256_store_si256((__m256i *)(lk + 8 * q), r[q]);
      }
      for (int k = 0; k < sn; k++) {
        const int sr = (int)(lk[k] & 127u);
        ltmp[2 * k] = S[2 * (l + sr)]; ltmp[2 * k + 1] = S[2 * (l + sr) + 1];
      }
    } else {
      // sn in (64,256]: sort each 64-key block with the fixed network, then merge pairwise.
      // sn in (64,256] -> 128 or 256 keys, PADDED TO THE FULL WIDTH so every merged span is
      // fully initialised (a 3-block span would otherwise expose stale keys from a prior call).
      const int lim = (sn <= 128) ? 128 : 256;       // power of two, each a tree of bm()'s
      const int nb = lim >> 6;
      for (int k = 0; k < sn; k++) lk[k] = (ley[k] << 8) | (u32)k;
      for (int k = sn; k < lim; k++) lk[k] = 0xFFFFFFFFu;
      for (int b = 0; b < nb; b++) {
        __m256i r[8];
        for (int q = 0; q < 8; q++) r[q] = _mm256_load_si256((const __m256i *)(lk + 64 * b + 8 * q));
        bs64(r);
        for (int q = 0; q < 8; q++) _mm256_store_si256((__m256i *)(lk + 64 * b + 8 * q), r[q]);
      }
      if (nb == 2) bm(lk, 128);
      else { bm(lk, 128); bm(lk + 128, 128); bm(lk, 256); }
      for (int k = 0; k < sn; k++) {
        const int sr = (int)(lk[k] & 255u);
        ltmp[2 * k] = S[2 * (l + sr)]; ltmp[2 * k + 1] = S[2 * (l + sr) + 1];
      }
    }
    for (int k = 0; k < sn; k++) { S[2 * (l + k)] = ltmp[2 * k]; S[2 * (l + k) + 1] = ltmp[2 * k + 1]; }
  }
  return in;
}

// returns the buffer holding the y-sorted range [l,r)
// FULL==0: leaves the rank counter EMPTY.   FULL==1: leaves [l,r) fully INSERTED.
template <int LV, int LF, int FULL, bool ROOT = false> static int cdq(int l, int r, int in) {
  int s = r - l;
  if (s <= 1) return in;
  if (s <= LF) {
    int bb = cdq_leaf(l, r, in);
    if (FULL) { u64 *Q = RC[bb]; for (int k = l; k < r; k++) zadd<LV>(W_R(Q[2 * k + 1])); }
    return bb;
  }
  int m = (l + r) >> 1;
  int mode = 3;
  const u64 *SI = RC[in];
  if (__builtin_expect(W_X(SI[2 * m - 1]) != W_X(SI[2 * m + 1]), 1)) mode = 0;
  else {
    u32 g = W_X(SI[2 * m + 1]);
    int a = m - 1; while (a > l && W_X(SI[2 * a - 1]) == W_X(SI[2 * a + 1])) a--;
    int b = m;     while (b < r && W_X(SI[2 * b - 1]) == W_X(SI[2 * b + 1])) b++;
    if (a == l && b == r) mode = 2;
    else {
      int lim = s >> 2;
      int ca = -1, cb = -1;
      if (a > l && a - l >= lim && r - a >= lim) ca = a;
      if (b < r && b - l >= lim && r - b >= lim) cb = b;
      if (ca >= 0 && (cb < 0 || m - ca <= cb - m)) { m = ca; mode = 1; }
      else if (cb >= 0) { m = cb; mode = 1; }
    }
  }
  if (FULL == 0 && (mode == 0 || mode == 1)) {
    // RIGHT child first (must end empty), then the LEFT child (ends holding all of [l,m)),
    // then a descending fuse that CONSUMES it.  No undo anywhere in this node.
    int b2 = cdq<LV, LF, 0>(m, r, in);
    int b1 = ROOT ? cdq<LV, LF, 0>(l, m, in) : cdq<LV, LF, 1>(l, m, in);
    if (b1 != b2) {
      memcpy(RC[b1] + 2 * m, RC[b2] + 2 * m, (size_t)(r - m) * 16);
      b2 = b1;
    }
    if (ROOT) { node_root_ascending<LV>(l, m, r, b1); return -1; }
    int out = 1 - b1;
    node_fused_desc<LV>(l, m, r, b1, out);
    return out;
  }
  int b1 = cdq<LV, LF, 0>(l, m, in);
  int b2 = cdq<LV, LF, 0>(m, r, in);
  if (b1 != b2) {
    memcpy(RC[b1] + 2 * m, RC[b2] + 2 * m, (size_t)(r - m) * 16);
    b2 = b1;
  }
  if (mode == 0 || mode == 1) {
    int out = 1 - b1;
    if (FULL) { node_fused_full<LV>(l, m, r, b1, out); return out; }
    node_fused<LV>(l, m, r, b1, out);
    return out;
  }
  if (mode == 2) {
    int out = 1 - b1;
    merge_run(l, m, r, b1, out);
    if (FULL) { u64 *Q = RC[out]; for (int k = l; k < r; k++) zadd<LV>(W_R(Q[2 * k + 1])); }
    return out;
  }
  // mode 3: x-tie spans the midpoint, no balanced group boundary: filtered passes
  {
    const u64 *S = RC[b1];
    u32 g = 0;
    for (int k = l; k < m; k++) { u32 xv = W_X(S[2 * k + 1]); if (xv > g) g = xv; }
    cross_filter<LV>(l, m, r, b1, g, 1);
    cross_filter<LV>(l, m, r, b1, g, 2);
  }
  int out = 1 - b1;
  merge_run(l, m, r, b1, out);
  if (FULL) { u64 *Q = RC[out]; for (int k = l; k < r; k++) zadd<LV>(W_R(Q[2 * k + 1])); }
  return out;
}

void count_3d(int n, const unsigned *x, const unsigned *y, const unsigned *z, unsigned *out) {
  if (n <= 1) { if (n == 1) out[0] = 0; return; }
  msk_init();

  // ---- z compression: T = #{z' < z}, R = unique rank in z order ----
  memset(H32, 0, (size_t)(n + 1) * 4);
  for (int i = 0; i < n; i++) {
    u32 h = H32[z[i]];
    if ((h & 0xFFFu) != 0xFFFu) H32[z[i]] = h + 1;      // clamp: never carry into the start field
  }
  {
    __m256i carry = _mm256_setzero_si256();
    int v = 0;
    for (; v + 8 <= n + 1; v += 8) {
      __m256i o = _mm256_loadu_si256((const __m256i *)(H32 + v));
      __m256i t = _mm256_add_epi32(o, _mm256_slli_si256(o, 4));
      t = _mm256_add_epi32(t, _mm256_slli_si256(t, 8));
      t = _mm256_add_epi32(t, _mm256_shuffle_epi32(_mm256_permute2x128_si256(t,t,0x08),0xff));
      __m256i total = _mm256_add_epi32(t, carry);
      __m256i ex = _mm256_sub_epi32(total, o);
      _mm256_storeu_si256((__m256i *)(H32 + v), _mm256_slli_epi32(ex,12));
      carry = _mm256_shuffle_epi32(_mm256_permute2x128_si256(total,total,0x11),0xff);
    }
    u32 acc = (u32)_mm256_extract_epi32(carry,0);
    for (; v <= n; v++) { u32 c=H32[v]&0xfffu;H32[v]=acc<<12;acc+=c; }
  }

  // ---- RADIX placement by x: 1024-bucket histogram (4 KB, L1) + a scatter into 1024 contiguous
  // ---- bucket regions (~64 KB of hot lines, L2) + a per-bucket counting sort on the low 10 bits.
  // ---- BOTH passes are STABLE, so the x-order AND the input-order tie break are identical to the
  // ---- old `CNT[x[i]]++` counting sort => byte-exact.  x < n <= 1e6 < 2^20, so x>>10 < 1024.
  static u64 SCT[2 * MAXN];
  static u32 ST10[1025];
  static u16 C16[1024];
  memset(CNT, 0, 1024 * 4);
  for (int i = 0; i < n; i++) {
    if (i + 16 < n) __builtin_prefetch(&CNT[x[i + 16] >> 10]);
    CNT[x[i] >> 10]++;
  }
  {
    u32 acc = 0;
    for (int v = 0; v < 1024; v++) { u32 c = CNT[v]; ST10[v] = acc; CNT[v] = acc; acc += c; }
    ST10[1024] = acc;
  }
  for (int i = 0; i < n; i++) {
    if (i + 96 < n) { __builtin_prefetch(&CNT[x[i + 96] >> 10]);
                      __builtin_prefetch(&SCT[2 * (size_t)CNT[x[i + 96] >> 10]]); }
    if (i + 48 < n) __builtin_prefetch(&H32[z[i + 48]]);
    u32 zv = z[i], h = H32[zv];
    u32 T = h >> 12, R = T + (h & 0xFFFu);
    if ((h & 0xFFFu) != 0xFFFu) H32[zv] = h + 1;
    u64 record = ((u64)T << 40) | ((u64)R << 20) | (u64)x[i];
    const u32 t = CNT[x[i] >> 10]++;
    _mm_storeu_si128((__m128i *)(void *)(SCT + 2 * t),
                     _mm_set_epi64x((long long)record, (long long)(((u64)y[i] << 40) | ((u64)i << 20))));
  }
  {
    u64 *D = RC[0];
    for (int b = 0; b < 1024; b++) {
      const int lo = (int)ST10[b], hi = (int)ST10[b + 1];
      if (hi <= lo) continue;
      if (hi-lo > 65535) {
        u32 wide[1024]={};
        for(int t=lo;t<hi;t++)wide[SCT[2*t+1]&1023u]++;
        u32 sum=0;for(int v=0;v<1024;v++){u32 c=wide[v];wide[v]=sum;sum+=c;}
        for(int t=lo;t<hi;t++){u32 p=(u32)lo+wide[SCT[2*t+1]&1023u]++;
          _mm_storeu_si128((__m128i*)(D+2*p),_mm_loadu_si128((const __m128i*)(SCT+2*t)));}
        continue;
      }
      memset(C16, 0, 1024 * 2);
      for (int t = lo; t < hi; t++) C16[SCT[2 * t + 1] & 1023u]++;
      __m256i carry = _mm256_setzero_si256();
      const __m256i b7w = _mm256_setr_epi8(14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,
                                           14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15);
      for (int v = 0; v < 1024; v += 16) {
        __m256i o = _mm256_loadu_si256((const __m256i *)(C16 + v));
        __m256i t = _mm256_add_epi16(o, _mm256_slli_si256(o,2));
        t = _mm256_add_epi16(t, _mm256_slli_si256(t,4));
        t = _mm256_add_epi16(t, _mm256_slli_si256(t,8));
        t = _mm256_add_epi16(t, _mm256_shuffle_epi8(_mm256_permute2x128_si256(t,t,0x08),b7w));
        __m256i total = _mm256_add_epi16(t,carry);
        _mm256_storeu_si256((__m256i *)(C16+v),_mm256_sub_epi16(total,o));
        carry = _mm256_shuffle_epi8(_mm256_permute2x128_si256(total,total,0x11),b7w);
      }
      for (int t = lo; t < hi; t++) {
        const u32 p = (u32)lo + (u32)C16[SCT[2 * t + 1] & 1023u]++;
        _mm_storeu_si128((__m128i *)(void *)(D + 2 * p),
                         _mm_loadu_si128((const __m128i *)(const void *)(SCT + 2 * t)));
      }
    }
  }
  // ---- tie bits over x-order positions ----
  // ---- CDQ ----
  // (ENGINE, SIZE)-dependent: measured optima are LF=16 at n=1e5 and LF=24 at n=1e6.
  int bb = (n <= 262144) ? cdq<3, 64, 0>(0, n, 0)
                         : (g_rootout = out, cdq<4, 256, 0, true>(0, n, 0));
  if (bb >= 0) {              /* [k09a-ROOT] bb < 0 => the root merge already wrote out[] */
    const u64 *D = RC[bb];
    for (int p = 0; p < n; p++) {
      if (p + 32 < n) __builtin_prefetch(&out[W_ORIG(D[2 * (p + 32)])]);
      out[W_ORIG(D[2 * p])] = W_A(D[2 * p]);
    }
  }
  g_rootout = 0;
}

CompilationN/AN/ACompile OKScore: N/A

Testcase #1135.538 ms49 MB + 796 KBAcceptedScore: 100


Judge Duck Online | 评测鸭在线
Server Time: 2026-11-04 02:11:21 | Loaded in 1 ms | Server Status
个人娱乐项目,仅供学习交流使用 | 捐赠