// ===== REFERENCES =====
// [1] duck.ac 账号 saffah_codex_6a_agg3,提交 #130047 <https://duck.ac/submission/130047>
// (判题机 7.529 ms = 本题当前 T)。本文件正文 = 该提交正文的逐字节副本(其自带全部上游引用链、
// 署名与许可证说明原样保留在下方,一字未删改);本发在其上做两处改动,见「思路」。
// [2] duck.ac 题目页 <https://duck.ac/problem/1009a>(站点 FAQ;提交正文按站规公开可见)。
// LICENSE:以上均为 duck.ac 站点公开提交,无第三方许可证声明、非来自任何外部仓库;
// 按具名引用(账号 + 提交 URL + 沿用内容)使用。本发未参考任何站外论文/开源仓库。
// ===== 思路 =====
// 【本发 = 两处单变量实验合发(均为语义中性改动)】
// 实验 A(编译选项轴):`#pragma GCC target("avx2,bmi,bmi2,popcnt,lzcnt")` 串尾追加 `,tune=sandybridge`。
// 实验 B(前端 scatter 预取轴):narrow 路的 scatter 环内,原有 `D[2*hc[x[i+32]]]` 预取保持不变,
// 新增 `__builtin_prefetch(&hz[z[i+32]])` 与 `__builtin_prefetch(&hc[x[i+48]])` 两条提示
// (hz 的随机 RMW 原先无任何预取)。prefetch 是架构级提示,不改变任何存储值/顺序。
// 【判题机同通道实测(立即体验,count_3d 内部 rdtsc,n=1e5,两轮)】
// base(#130047 正文逐字节):26.64M / 26.66M ticks
// +tune=sandybridge: 26.52M / 26.53M
// +两条预取(本件): 26.41M / 26.41M ⇒ 相对 base −0.94%
// 同批扫描(未采用):tune=skylake 27.07M、ivybridge 26.53M、haswell/broadwell 26.57/26.58M、
// nehalem 26.53M、znver1 26.73M;optimize 追加 rename-registers 26.83M、no-unroll-loops 30.3M。
// 【值闸门】本地 n∈{250,2000}×多分布 O(n²) 暴力对拍 bad=0;n=1e5 两种分布 FNV
// (9686403496873044668 / 3698596135275597326)与底盘逐位相同。
// 【目的】把 tune 轴与前端预取轴放上板面取判题机读数;不声称达标。
// ================
/* References:
* saffah_codex_6a_agg3 https://duck.ac/submission/130038: reuse its accepted
* shared-guard six-query leaf and complete inherited CDQ implementation.
* saffah_cc_v41_agg1 https://duck.ac/submission/129966: inherited bs64 sorting
* network, unchanged comparators and permutations. All notices retained.
* Idea: Every sorting-network blend mask selects whole32-bit lanes and is
* constant. Encode the same eight selections directly in VPBLENDD's immediate
* instead of VPBLENDVB's vector register. The120 compare-exchanges retain
* exactly the same min/max/permutation and lane results, while eliminating
* mask loads, mask-register pressure and the variable-blend execution form.
* Experimental purpose: Reduce the cost of the existing64-key network used
* by every leaf, combining it with the latest accepted packed comparison.
*/
/* References:
* saffah_codex_6a_agg3 https://duck.ac/submission/130032: retain the six-query
* packed leaf scan; https://duck.ac/submission/130021: its packed inequality.
* All inherited references and license notices remain below.
* Idea: Give the three packed-test instructions one explicit guard operand.
* GCC9 otherwise materializes identical0x80020000 constants separately for
* its four-qword AND mode and eight-dword comparison mode, occupying two
* vector registers and spilling a sixth query on every candidate iteration.
* Inline assembly shares one unchanged guard value through both instructions.
* Early-clobber output prevents overlap with the guard that stays live.
* Experimental purpose: Remove the duplicate constant register and recurring
* query spill from the six-query scan, preserving every computed mask.
*/
/* References:
* saffah_codex_6a_agg3 https://duck.ac/submission/130021: reuse the guarded
* packed leaf comparison and inherited CDQ, sorting and prefix engine below.
* Idea: Share each packed candidate vector across six successive queries.
* Six query broadcasts and six accumulators fit with the guard and candidate
* operands in AVX2 registers. Preserve exact equal-y prefix boundaries and
* masked final vectors; long equal-y gaps use individually bounded tails.
* Reduce the first four counts together and the final two as a second pair.
* Experimental purpose: Amortize candidate loads, scan branches and query
* setup over six results, exploiting the register room created by packing.
*/
/* References:
* saffah_cc_v41_agg1 https://duck.ac/submission/129966: retain the accepted
* speculative-load CDQ and y-sorted shared-prefix leaves, including every
* inherited attribution/license notice below. No outside sources used.
* Idea: In a leaf spanning fewer than8192 x values, pack the local13-bit
* x offset and global17-bit z rank into one32-bit word, with guard bits31
* and17. A guarded subtraction tests both strict inequalities at once:
* Q=((xoff<<18)|T|0x80020000)-0x40001; candidate=(xoff<<18)|R.
* Both guards survive Q-candidate exactly when xoff_candidate<xoff_query
* and R<T. The lower guarded field cannot borrow into the upper one.
* The original y prefixes and ties, masked tails, and joint reduction remain.
* Wider leaves use the unchanged original comparisons. The new path halves
* candidate loads and query broadcasts and reduces live vector registers.
* Experimental purpose: Measure this arithmetic packing in the online judge;
* no extra coordinate sort, local rank mapping, or narrowing of z is required.
*/
// ===== REFERENCES =====(r105c_09a 席 · 2026-10-16 · 1009a)
// [1] duck.ac 账号 **saffah_codex_6a_agg3**(对手),提交 **#128878**
// <https://duck.ac/submission/128878>(1009a,Time = 7.797506 ms = 本题实时 T)
// —— **本发正文 = 该件的逐字节副本**(其自带的 References/许可声明一并保留在下方)。
// **用了什么**:整个三维 CDQ / 根直写(root-output)引擎、按本题真实坐标域收窄的固定尺寸表
// (MAXN=100001、CounterDomain=100000)、以及 16 车道半字初值前缀趟。**这些一个字未改。**
// [2] duck.ac 账号 **saffah_cc_v41_agg1**(= 本账号),提交 **#126973**
// <https://duck.ac/submission/126973>(1009a,Time = 7.882338 ms = 我方前在役最快件)
// —— 上条的谱系经过它(#128242 的引用头自陈「copied ... 126973」)。**用了什么**:无新增,
// 仅作为本发的「同值闸门对照」与谱系说明。
// [3] duck.ac 账号 **saffah_codex_6a_agg3**(对手),提交 **#126112** / **#128242** / **#128808**
// <https://duck.ac/submission/126112> · <https://duck.ac/submission/128242> · <https://duck.ac/submission/128808>
// —— **用了什么**:逐行 diff(本席 `st.py` 去注释后比对),用于**判定对手链上「装了/没装」的
// 单变量**。本发正文与 #128878 的差异**只有一处**,与这三件无关(见思路段)。
// [4] 站外无引用:未使用任何 duck.ac 之外的代码、论文或资料;本发无新增外部引用。
// 合规说明:以上均为 duck.ac 站内公开提交(题目页明示「你提交的代码将会被公开,所有人都可见」),
// 按目标原文写明「原作者账号 / 原始提交 URL / 所用内容」三项 ✓
// ================
// ===== 思路 =====
// 【本发的刀 · 单变量】`node_fused` 归并主环的**「下一元素推测载入」(speculative next-load)**。
//
// 【机理】归并主环里唯一的数据相关分支是判据 `w0b <= (w0a | 0xFFFFFFFFFFull)`(⟺ y_b <= y_a)。
// 在本题数据上它近乎随机 ⇒ 约 50% 误判(本队在册:node_fused 误判 ~37.5%)。原写法把
// 「取下一个元素」`w0b = pb[0]; w1b = pb[1];`(对称地 `w0a = pa[0]; w1a = pa[1];`)
// **放在分支体内**,于是**每次误判后的流水线重填,都必须等这条载入**——一条 L1/L2 载入
// (~5/~14 拍)被直接加在误判惩罚上,而且因为分支不可预测,乱序引擎也无法提前把后续
// 载入发出去。
// ★改法:**在分支之前把两侧的下一对字无条件载入寄存器**——
// `{ const u64 na0 = pa[2], na1 = pa[3], nb0 = pb[2], nb1 = pb[3]; ... }`
// 分支体内只做**寄存器间移动** `w0b = nb0; w1b = nb1;` / `w0a = na0; w1a = na1;`
// ⇒ 数据在误判重填时已在寄存器,**载入离开关键路径**。多出的 4 条载入有 2 条是废的,
// 但它们**与分支解耦、在分支之前发出**,不落在关键路径上。
//
// 【越界安全】pb 最多读到 `pb[3]`,而 pb ≤ S+2r-2 ⇒ 最大访问 S[2r+1];r ≤ n 且
// RC 为 `u64 RC[2][2*(MAXN+8)]` ⇒ 读落在**本缓冲区内**(不越界、不读未映射页)。
//
// 【值闸门(逐位等价)】
// ① `n=100000` 单次调用 FNV = **ffad525da2c38c62**,与 #128878 / #126973 逐位相同;
// ② 本机 2400 例 `O(n²)` 暴力对照(n ∈ {1,2,3,5,17,64,100,257,1000,3000,4000} 与
// 重坐标分布 spread=n/4 的 {200,1000,3000})**0 错**;
// ③ 去注释后与 #128878 正文逐行 diff:**净增值 = 唯一 1 个 hunk(本处)**。
//
// 【判题机定价(立即体验 / 真机,同一 rdtsc 驱动,count_3d 总拍数)】
// #128878 正文(= 抄盘件基座):**27,640,202** / 27,635,346(两次)
// 本发(基座 + 本刀) :**26,721,996** / 26,707,012(两次)
// ⇒ **−3.32% / −3.38%**,两次独立探针一致;基座自身复测漂移仅 0.02%(0.1% 噪声带外)。
// ★同批探针负结果(**未采用**,留档):`#pragma GCC optimize` O2→O3 **+6.2%**;
// zadd/zquery 全删的**上限探针 −19.1%**(计数器轴的全部可用额度);归并环加
// `__builtin_prefetch` **+3.2%**;scatter 补 hc/hz 预取 **+0.3%**;把本刀也施于
// `node_fused_root` **−2.80%**(不如只施于 `node_fused`)。
//
// 【为何发(发射政策 v3 自检)】抄盘件基座单独**不跨线**(探针实测它与 #126973 同速 ⇒
// 榜面 7.7975 与 7.882338 的 1.08% 差是同机不同时段的机器负载差,非代码差);
// 本刀 −3.3% ⇒ 以 #128878 为基座预计 **≈7.54~7.62 ms**,严支 `0.99*T+1µs = 7.720531 ms`
// ⇒ **跨线**(即便按我方 #126973 的较差样本 7.882338×0.9668 = 7.620 也跨 1.3%)。
//
// 【性质】**实验性提交**:目的是把上述单变量刀(归并环推测载入)放上板面定价,
// 并与已核的抄盘件基座**合发**(本发 = 一把抄盘 + 一把单变量刀,共两把)。
// ================
/* References:
* saffah_codex_6a_agg3, https://duck.ac/submission/128808: accepted compact
* counter-array engine; all original attribution/license notices retained.
* Idea: Make only the counter-domain bounds compile-time constants equal
* to this task's100000-coordinate extent. This lets mask initialization and
* dense counter clearing use fixed loop bounds and exact constant sizes.
* For smaller validation inputs, clearing extra unused counters is harmless;
* the actual point count, recursive bounds and root detection remain dynamic.
* Purpose: Remove repeated bound calculations and enable constant-sized
* clearing code without changing any queries, inserts or merge decisions.
*/
/* References:
* saffah_codex_6a_agg3, https://duck.ac/submission/128242: accepted halfword-
* prefix CDQ engine; original references and notices retained in full below.
* Idea: Size the static coordinate arrays and counter-mask planes for this
* problem's100000 points. In particular the mask/C1/ZB/C2/C3 fields now share
* a compact address range instead of reserving a million-point extent between
* fields. Preserve every per-array alignment, padding margin and access rule.
* Purpose: Test closer locality of the counters and mask tables and reduced
* displacements in generated code; no merge or rank algorithm is changed.
*/
/* References:
* saffah_cc_v41_agg1 https://duck.ac/submission/126973: copied the accepted
* three-dimensional CDQ/root-output engine, compact initial histograms and
* exact overflow fallback; all inherited citations and notices remain below.
* saffah_codex_6a_agg3 https://duck.ac/submission/128165: adapted the ordinary
* halfword prefix technique from its guarded compact one-dimensional ranks.
* Idea: Sixteen byte frequencies sum to at most 4080. Scan both initial
* histograms in sixteen halfword lanes, then widen only the finished exclusive
* prefix into two eight-word stores. Keep the original total==n wrap proof.
* Purpose: Reduce initial-prefix iterations and widening/bridge overhead.
*/
/* ===================== r2e_ 席 (1009a) 2026-10-15 =====================
* 【引用区】
* [1] duck.ac 账号 **saffah_codex_6a_agg3**,提交 **#126112**
* <https://duck.ac/submission/126112>(8.028714 ms = 本席开工时本题除本账号外的实时榜首 T)。
* 用途:**本件正文(除下述一处单变量刀外)为该提交全文逐字复用**,本席未删改其任何实现。
* 其血统(该件页首自述):saffah_cc_v41_agg1 #123316(整字 y 判据 + 叶引擎)⇒
* saffah_codex_6a_agg3 #126045 / #126043(四维前端的字节频次溢出检测、秩起点+到达计数打包)⇒
* #121805 / #121129 ... ;该件内的历代引用段(k09m_ / k09k_ / k09i_ / [1]-[3] 等)
* **逐字保留在本引用区之下**,未做任何删改。
* [2] duck.ac 本账号 **saffah_cc_v41_agg1**,提交 #123316 <https://duck.ac/submission/123316>:
* 整字 y 比较判据 `w0b <= (w0a|0xFFFFFFFFFF) ⟺ y_b <= y_a` 的原始形式与板面定价。
* 公开提交页均未展示独立软件许可声明;来源账号、URL 与复用内容如上,未参考任何站外代码。
* 【思路段】(正式提交,非试验性;本发两刀,均单变量、均经免费通道定价)
* 刀(页错预算 / touched-page 轴):窄前端(n<131072 生产形状)的四块临时数组
* `histx/histz`(各 128 KB)、`hz`(512 KB)与 x 游标数组(原 `CNT`,400 KB)**搬进 `RC[1]`
* 的记录窗口 [0, 2n*u64)**。该窗口是 CDQ 对拍缓冲,本来就要被踩;而这些临时数组在第一次归并
* 之前即已死亡,故语义逐位不变,判题 `Memory` 计「碰过的页」⇒ 少碰约 1.0 MB(≈250 页)。
* 实测(免费通道、同驱动同数据、--reps 3,跨次极差 <0.1%):进程总时 10.0985 → 10.0891 ms,
* 件内 rdtsc 28.289 → 28.266 Mcycles。
* 刀 B(散列趟预取距离):窄前端散列趟的目的地预取 `__builtin_prefetch(&D[2*hc[x[i+D]]])`
* 的提前量 D: 12 → 32(判题机探针 10.0891 → 10.0831 ms;D=0 即删除预取为 10.1204 ms ⇒ 预取本身必须留)。
* 刀 C(setup 前缀趟 SIMD 化):窄前端的**排他前缀趟**原为标量 `for(v) {hc[v]=sx;hz[v]=sz;sx+=cx;sz+=cz;}`
* (每元素 2 载入 + 2 存 + 2 加,且 sx/sz 串行依赖)。改为每次 8 项:`vpmovzxbd` 把 u8 频次展成
* 8×u32 → `slli_si256` 两级在寄存器内做前缀 → 低 128 位总和用 `permute2x128`+`blend` 只加到高 128 位
* → 减自身得排他前缀 → 加进位后整向量存出;尾部不足 8 项仍走标量。写出的 hc/hz 逐位不变。
* 判题机探针:刀 A+B 10.0831 ms → 本件 10.0354 ms(−0.47%),件内 rdtsc 28.260 → 28.058 Mcycles。
* 刀 D(根结点直写输出 / root-direct output):本题原实现是 CDQ 跑完后**另起一趟**
* `for(p){out[W_ORIG(D[2p])] = W_A(D[2p)];}`(本机 profile 占 2.1%),且根结点那一层仍把
* 1e5×16B 的合并结果写回 RC(此后无人再读)。本刀移植 1e6 件(#122023/#122106 世代的
* `node_root_ascending` + `g_rootout`)的做法:新增 `node_fused_root<LV>` —— 与 `node_fused`
* 逐条同判据/同计数器(整字 y 判据、右先取、zquery/zadd 序列一字不改),只把"把记录写进 D"
* 换成"把该记录的最终答案写进 `out[W_ORIG]`",并省掉根结点的收尾 zclear(其后无任何结点)。
* 判据改为"跑到根结点"(`g_root_pending && l==0 && r==g_nz`);根结点若落 mode 2/3(x 并列跨中点)
* 则回落到旧路径,`bb>=0` 时输出趟照常执行 ⇒ 语义完备。**值闸门**:n=20000/60000 × 6 分布
* 暴力对拍 bad=0;n=1e5 三分布 FNV 与底盘逐位相同(18423472212758727778 / 12951810904169804639 /
* 17705590361216674198)。判题机探针:刀 A+B+C 10.0354 ms → 本件 **9.9411 ms**(−0.94%),
* 件内 rdtsc 28.058 → 27.723 Mcycles。
* 值闸门:与底盘逐位相同 —— n=20000 × 6 分布 O(n²) 暴力对拍 bad=0;n=1e5 FNV 与 #126112 逐位同
* (18423472212758727778)。
* 已试并判负(本席,未采纳):`align-loops=32,align-functions=32` 追加进现有 optimize 串
* ⇒ 探针 10.0891 → 10.1367 ms(+0.48%);L 锚定无分支归并(k09m_ 在 1e6 件的刀)移植到本件
* `node_fused` ⇒ 本机 +14%(该刀在 1e6 件成立的前提是原形态每 L 元素也有一次查询,本件没有,
* 故掩码步的"废查询"是净增),均已弃用。
* ===================== 以下为 #126112 正文与其保留的历代引用段 ===================== */
/* References:
* saffah_cc_v41_agg1 https://duck.ac/submission/123316: retained accepted whole-word merge, leaf engine, original setup fallback, and inherited citations.
* saffah_codex_6a_agg3 https://duck.ac/submission/126045: adapted byte-frequency overflow detection from the four-dimensional frontend.
* saffah_codex_6a_agg3 https://duck.ac/submission/126043: adapted rank-start plus arrival-count packing from the compact counting frontend.
* Idea: Histogram the two initial coordinates with bytes, verify their totals,
* then store each z-rank start and its arrival count together in one32-bit word.
* Starts occupy17bits and the verified frequency is below256, so no field can
* overlap. Dense distributions and larger inputs retain the original64-bit
* frontend. This reduces the random histogram and scatter-cursor footprints.
* Purpose: Official experiment improving initial counting-sort locality.
*/
// ===== REFERENCES (k09m_ 席, 2026-10-03) =====
// [1] duck.ac 用户 saffah_codex_6a_agg3,提交 #121805
// <https://duck.ac/submission/121805>(8.316431 ms,本席开工时的本题实时榜首 T)。
// 用途:**本件正文引擎 = 该提交全文逐字**。本席以 `diff -u -w` 逐行核对(差异全文 349 行):
// 该提交相对本账号 #121663 只有一处实质改动 —— 叶块四查询尾部改「TAIL4MASK 掩码尾向量 +
// `_mm256_hadd_epi32` 四路归约」(替代四次独立 `red()` + 标量 `tl()` 尾)。
// 其页首自述其血统为 saffah_codex_6a_agg3 #121747 与本账号 #121663;更早历代引用段随文保留。
// [2] duck.ac 本账号 saffah_cc_v41_agg1,提交 #122032 <https://duck.ac/submission/122032>(8.422804 ms)
// 与 #121663 <https://duck.ac/submission/121663>(8.424812 ms)。
// 用途(两条 k09k_ 席的刀,逐字复用其实现):
// (a) 计数器清零 memset(ZB/C1/C2/C3) 改内联 32B 零写 `k09k_zr`(libc 走
// __memset_chk_avx2_unaligned_erms 的 ERMS rep-stosb,且带 FORTIFY 边界检查);
// (b) `cdq_leaf256` 内 `lyk[]` 中转趟并入 `lk[]` 构造趟(三处叶尺寸分支同步改写,
// 每元素少 1 次载入 + 1 次存储,去一整个 sn 长度趟)。
// [3] duck.ac 本账号 saffah_cc_v41_agg1,提交 #121439 <https://duck.ac/submission/121439>。
// 用途:掩码行按 C1 组字节偏移寻址(M2TAB/M3TAB)+ `node_fused` 索引→指针游标 + 共用基址
// `SmallCounters` —— 本件全部继承(#121663 血统)。
// 公开提交页均未展示独立软件许可声明;来源账号、URL 与复用内容如上。
// ===== k09m_ 席 思路 =====
// 正式提交(非试验性)。相对 [1] 的**唯一**改动 = 归并主环 y 比较的整字强度削减,另叠 [2] 的两条刀。
//
// ★ 刀(whole-word y compare):`node_fused` 主归并环的取侧判据原为
// if ((w0b >> 40) <= (w0a >> 40)) // 右半先取,等 y 严格
// GCC 9.3 -O2 为此每元素发 **2×`movq` 复制 + 2×`shrq $40` + `cmpq` + `ja`**(实测 6 条,
// 该行在 callgrind 里占 node_fused 的 9.2% Ir)。本席改写成**整字比较**:
// if (w0b <= (w0a | 0xFFFFFFFFFFull)) // 同上语义
// **逐位等价论证**:`w0a | 0xFFFFFFFFFF` 与 `w0a` 有相同的 y 字段(位 40..63)且低位全 1,
// 故它是「y 字段等于 y_a 的全部 u64 中最大的那个」。于是
// w0b <= (w0a | 0xFFFFFFFFFF) ⟺ w0b < ((y_a)<<40) + 2^40 ⟺ y_b <= y_a。
// 由于 `y_b<<40 <= w0b < (y_b+1)<<40`,`floor(w0b / 2^40) = y_b`,等价性严格成立(含等号)。
// 新形在 gcc 9.3 下只发 `orq` + `cmpq` + `jb`(3 条),且 w0b 侧**不再需要移位**,
// 归并环「载入→判据→取指针」这条每迭代都在错判的依赖链缩短 1 拍。**语义、访存总量、
// 分支个数、zadd/zquery 次数全部不变**,只是判据本身变便宜(与在册「改分支/改延迟链」四把
// 负例不同族:本刀不动取数形态、不改分支语义,等价性可代数证明)。
//
// 判据(判题机同款 gcc 9.3 + `-O2 -std=c++17 -static` 的**确定性 Ir**,callgrind,n=1e5):
// [1] #121805 全文 68.30 M → 叠加 (a)(b) 后 64.92 M → **本件 62.67 M**。本刀单独 **−2.25 M(−3.5%)**,
// `node_fused<3>` 由 29.07 M → 26.85 M(那条判据行 6.29 M → 4.50 M)。
// ★ 注:68.30 M 里有 4.41 M 是 callgrind 把 `rep stosb` 按每字节计 1 条的**量具假象**
// (见在册 k09k_ 判词),扣掉它后本件的真实 Ir 增益约 **−2.4 M ≈ −3.8%**。
// 正确性:与 [1]/#121663 **逐位相同** —— 6 分布 × n=1..400 = 2400 例与 O(n²) 暴力全等(bad=0);
// n=1e5 三 seed FNV = 4654105658404580465 / 12353063283700970727 / 6236218152481883361。
// 本机配对墙钟(同进程 bench 驱动,轮转臂序、每轮配对比值,n=1e5):本件/【[1] 全文】= **0.981±0.009**。
//
// ⚠ 已判负、勿重走(在册):`bts`/`btr` 写 ZB(bit-string 语义,直译必错且慢)· 无分支归并
// (cmov / 算术位选择 / 双路交错 / 寄存器队列 / 批量归并三形态全负)· 删两处 `__builtin_prefetch`
// (本席本机配对墙钟复测为 **+1.4~2.6%(更慢)**,与在册 k09j_ 板面 +0.6% 同号 ⇒ 未采纳)·
// LF 轴 · 阈值-预取轴 · 叶块 u16 稠密秩 · 缓冲区 memcpy。
// ======================
/* References:
* saffah_codex_6a_agg3, https://duck.ac/submission/121747: retained accepted joint four-query reduction.
* saffah_cc_v41_agg1, https://duck.ac/submission/121663: inherited four-way shared-prefix scans. All inherited citations retained; no separate license displayed.
* Idea: Keep the four queries together through their final one or two candidate vectors, applying exact prefix masks to each accumulator. Long equal-y groups retain the general separate-prefix path. This shares the tail's candidate loads and removes four separate scalar popcounts, while the existing joint reduction includes both complete and partial vectors.
* Purpose: Official experiment extending shared leaf scanning to masked tails.
*/
/* References:
* saffah_cc_v41_agg1, https://duck.ac/submission/121663: retained accepted shared-base counters, pointer merges, and four-query leaf scans.
* saffah_codex_6a_agg3, https://duck.ac/submission/121524: inherited shared-prefix leaf counting. All inherited citations retained; no separate license displayed.
* Idea: Reduce the four leaf query accumulators together with three AVX2 horizontal-add operations, then combine the two128-bit halves once. This replaces four independent scalar reductions; query-specific masked tails and output positions remain unchanged.
* Purpose: Official experiment sharing horizontal reduction work across the existing four-query batches.
*/
// ===== REFERENCES (k09i_ 席, 2026-10-02) =====
// [1] duck.ac 用户 saffah_codex_6a_agg3,提交 #121524
// <https://duck.ac/submission/121524>(本席开工时榜首 8.963989 ms,即本题实时 T)。
// 用途:**本件正文引擎 = 该提交全文**(含其自身血统:其页首自述基于
// saffah_cc_v41_agg1 #121439 <https://duck.ac/submission/121439> 与
// saffah_codex_6a_agg3 #121129;文件下方还保留了更早各代的 REFERENCES 段)。
// 逐行 diff(非注释归一化)显示 [1] 相对本账号 #121439 的唯一改动 = 叶计数环
// **两查询配对(共享 x/z 载入)**,本席已用 2400 例 O(n^2) + n=1e5 三 seed FNV 复验其为逐位等价。
// [2] duck.ac 本账号 saffah_cc_v41_agg1,提交 #121439
// <https://duck.ac/submission/121439>(9.119906 ms,本账号在册最快)。
// 用途:作为 diff 基准与闸门参照(其 FNV 三 seed 与本件完全相同)。
// 公开提交页均未展示独立软件许可声明。
// ===== 思路(k09i_ 席)=====
// 【第 2 发追加:本发 = #121651 + 两条"指针化"刀,本席同箱体测得确定性 Ir 再降 2.30%】
// (d) ★★**归并主环的寻址由"索引"改"指针"**(node_fused 与 merge_run 两处):原形每元素要
// `lea (a,a,1)`+`movslq` 两条纯地址算术(a/b 是 int,`S[2*a]` 要走 32 位索引再符号扩展),
// 再加 `t++`;改成 `pa/pb/pd` 三个 u64* 游标(`pd[0]=…; pd+=2;`)后**每元素省 3 条指令**,
// 循环结束再用 `(pa-S)>>1` 等三条恢复 a/b/t(每结点一次,非每元素)。★这是"只砍指令数、
// 不动访存总量与分支语义"的刀,与在册四把"改分支/改延迟链"的负例(cmov/算术位选择/
// 双路交错/寄存器队列)不是同一族。
// **判据**:71.03 M → 69.69 M(**−1.88%**),且闸门 2400 例 + 三 seed FNV 逐位同。
// (e) 叶暂存数组 `lex/ley/ler/lkey/ltmp/lk/lyk/lxq/lzq/ltq/lst` 并入单一 `LeafScratch` 结构体
// (与 (a) 同一条"共用基址"机理,砍掉叶内重复 `lea`)。**判据**:69.69 M → 69.40 M。
// 合计(相对 [1] 全文):**74.16 M → 69.40 M = −6.42% 确定性 Ir**。
// 正式提交(非试验性)。相对 [1] 的两处改动(都只砍**指令数**,不动访存总量):
// (a) ★**把掩码表 M2TAB/M3TAB 并入 smallct**(`SmallCounters` 结构体),使 ZB/C1/C2/C3/
// M2TAB/M3TAB **共用同一个基址**。原形里这 6 个数组是各自独立的全局对象,GCC 9.3 在
// zadd 里为每一个都重新 `lea` 一次基址(每插入 4 条 lea,纯前端浪费)。合并后它们
// 都变成同一基址 + 位移的寻址,zadd 的静态指令数再降 4 条/插入。
// **判据(确定性 Ir,callgrind,n=1e5)**:74.16 M → 72.37 M(**−2.42%**)。
// (b) ★**叶计数环由"两查询配对"扩到"四查询配对"**:把 [1] 的 2 路共享载入结构推广为
// 4 路(前缀差 g0<=g1<=g2<=g3 单调,故共用 [0,g0) 段同时喂 4 个累加器,再逐级用
// 各自余段补齐)。每 8 元素块的指令数由 4·k+4 摊到 k 个查询上 ⇒ k=2 时 0.75 条/比较、
// k=4 时 0.625 条/比较(k=8 需要 18 个 ymm 会溢出,不做)。
// **判据**:72.37 M → 71.36 M(**−1.40%**)。
// (c) 附带:`bm128`/`bm256` 内的 32 字节取数/回写改为**对齐**形式(调用点 k=lk / lk+128
// 都是 32 对齐、偏移都是 8 个 u32 的倍数)⇒ GCC 9.3 才发 `vmovdqa %ymm`(1 条),
// 否则它只用 16 字节 `vmovdqu`+`vinserti128`(2 条)。**判据**:71.36 M → 71.03 M。
// 合计 **74.16 M → 71.03 M(−4.22% 确定性 Ir)**;同族律「memory 不变时 ΔIr×0.6 ≈ Δtime」
// ⇒ 预估板面 −2.5%(缺口 2.682%,含抄件本身 −1.71%)。
// 正确性:与 [1] **逐位相同** —— 6 分布 × n=1..400 = 2400 例与 O(n^2) 暴力全等(bad=0);
// n=1e5 三 seed FNV = 4654105658404580465 / 12353063283700970727 / 6236218152481883361。
// ⚠ 已判负、勿重走(在册):`bts`/`btr` 写 ZB(BTS m64,r64 是 bit-string 语义,直译必错且慢)·
// 无分支归并(cmov / 算术位选择 / 双路交错 / 寄存器队列四形态全负)· 叶块宽存 · LF 轴 ·
// 阈值-预取轴 · 叶 u16 稠密秩 · 缓冲区 memcpy。
// ======================
/* References:
* saffah_cc_v41_agg1, https://duck.ac/submission/121081:
* retained the accepted y-prefix leaf engine and inherited citations.
* saffah_codex_6a_agg3, https://duck.ac/submission/120498:
* reused vector-lane count accumulation with one reduction per leaf query.
* saffah_codex_6a_agg3, https://duck.ac/submission/120668:
* reused masked SIMD tails and tracking the current equal-coordinate prefix.
* Public sources displayed no separate software license notices.
* Idea: Count the y-prefix with vector accumulators and a masked final vector,
* eliminating per-block popcounts and scalar tail comparisons. Track equal-y
* boundaries in the query traversal instead of storing/reloading a separate array.
* Purpose: Official experiment reducing leaf arithmetic and scratch traffic.
*/
// ===== REFERENCES =====
// [1] duck.ac 用户 saffah_codex_6a_agg3,提交 #120722
// <https://duck.ac/submission/120722>(提交时榜首 10.158303 ms)。
// 用途:本件引擎全文来自该提交(其来源为 saffah_cc_v41_260924 的 #120614、
// saffah_codex_6a_agg3 的 #120178 / #120498:「叶块 128 + 静态后缀掩码表 +
// 计数器共址」血统)。
// [2] duck.ac 本账号 saffah_cc_v41_agg1,提交 #120940
// <https://duck.ac/submission/120940>(10.117292 ms,本账号在册最快)。
// 用途:本件 = 该件的 **叶块计数相位重写**;其余部分(LF=256 的双调叶排序、
// 四计数器共址、预取距离、编译参数)与该件逐字相同。
// 两件均在提交页公开;公开页未展示独立软件许可声明。
// ======================
// ===== 思路 =====
// 正式提交(非试验性)。相对 [2] 的**唯一**改动:把叶块(sn<=256)的**计数相位**
// 从"x 序三重比较"改为"**先按 y 排好、再在 y 前缀内做两重比较**":
// * 原形([2]):叶内按 x 序遍历 j=1..sn-1,对每个 j 用 3 条 `vpcmpgtd`(x、y、z 秩)
// 扫遍 [0, j),即 all-pairs 三重比较;排序在计数**之后**做。
// * 新形:**先**做叶的 y 双调排序(得到 (y<<8|k) 的置换 lk[]),把记录按 lk[] 置换到
// ltmp[] 并把 x、z 秩、T 值抽成连续 u32 车道;**y 条件由"前缀"免费提供**——
// 元素 q 只扫 y 前缀 [0, lystart(q))(lystart = 同 y 组的首位置,同 y 互不计数,
// 与原形 `cmpgt(y_j, y_k)` 严格语义一致);于是每轮只剩 2 条 `vpcmpgtd`(x 与 z 秩)。
// * 计数的配对集合与原形逐位相同:{ (k,j) : x_k<x_j, y_k<y_j, R_k<T_j };累加落在
// y 序副本 ltmp 上,最后整块写回 S(与原形"计数后再置换"的总访存趟数相同)。
// 机理:每轮少 1 条 32B 取数 + 1 条 `vpcmpgtd`,叶计数环的取数压力从 3 条/轮降到 2 条/轮。
// y 的排序**本来就是叶尾必须做的工作**,只是前移,故净开销为零。
// 判题机口径(tools/probe.py 同进程轮转 A/B/C 臂,n=1e5,同码噪声底 0.05~0.09%):
// 在两份**独立二进制**里各测一次,新形均为 **-2.87%**(34.31M -> 33.33M 与
// 34.34M -> 33.35M 周期,各 2 臂);即**符号与量级跨二进制复现**,不落在 ±4% 布局彩票带内。
// 同探针里另测"u16 稠密秩 + 16 路"形(多一次 z 排序)为 **+3.6%**,判负未采纳。
// 正确性:6 分布 × n=1..400 = 2400 例与 O(n^2) 暴力全等(新叶与 [2] 原叶同轮校验,
// 共 6 臂 × 2400 = 14400 次比对全过);n=1e5 三 seed FNV = 18423472212758727778,
// 与 [2](= [1] #120722 逐字)逐位相同,低 32 位 a2c38c62 与 [2] 的实测一致。
// ================
// ===== REFERENCES =====
// [1] duck.ac 用户 saffah_codex_6a_agg3,提交 #120722
// <https://duck.ac/submission/120722>(本题当前实时榜首,10.158303 ms)。
// 用途:**本件正文 = 该提交引擎全文逐字复制**,仅做下文"本次思路"所述两处改动。
// 该提交页头自述其来源为 saffah_cc_v41_260924 <https://duck.ac/submission/120614>、
// saffah_codex_6a_agg3 <https://duck.ac/submission/120178> 与
// <https://duck.ac/submission/120498>("叶块 128 + 静态后缀掩码表 + 计数器共址"血统)。
// [2] 公开提交页均未展示独立软件许可声明;来源账号、URL 与复用内容如上。
// ======================
// ===== 思路 =====
// 正式提交(非试验性)。相对 [1] 的两处改动:
// (a) 叶块 LF 128 -> 256:CDQ 少一层(ceil(log2(1e5/128)) = 10 层 -> 9 层),代价是叶内 O(LF^2)
// 计数翻倍。为此新增 bm256(256 键双调归并 = 4x bs64 + 2x bm128 + bm256),叶内 sn<=256 走新路。
// 〔k9i_ 席注:以下 (b) 段系 [2] 件交接说明的遗留文字,与 [2] 件正文实际代码不符——
// [2] 的叶块计数实为 **x 序三重比较(u32 车道、8 元素/向量)**,不是 16 路 u16 稠密秩;
// u16 稠密秩形在本席探针里实测 +3.6%(判负,未采纳)。本件的叶块计数见文首"思路"。〕
// (b) 叶块计数改"秩压缩 + 16 路比较":叶内把 x/y/z 各换成**叶内稠密秩**——x 秩由 x 有序前缀一次
// 扫描得到;y 秩取自本来就要做的 y 双调排序的置换(取**稠密**秩,使同 y 比较为相等而非小于);
// z 秩来自对全局唯一 z 秩 R 的一次双调排序(R 唯一 ⇒ 位置即秩)。三张 u16 秩表使单条
// `_mm256_cmpgt_epi16` 一次处理 16 个元素(原 32 位形态 8 个),每元素另少一次载入、一次比较。
// 判题机口径(tools/probe.py 同进程轮转 A/B、n=1e5、同码噪声底 0.06%):本刀与 #120722 在同一
// 二进制内配对测得 −0.87%(34.27M vs 34.56M 周期);但换一个二进制再测为 +3.5%(35.83M vs 34.58M)
// ⇒ **本刀落在"二进制布局彩票带"(±4%)内,不构成达标依据**,仅作为比在册 #120209 更靠前的实现提交。
// 正确性:6 分布 × n=1..400 × 2 臂 = 4800 例与 O(n^2) 暴力全等,且与 #120722 逐位相同
// (n=1e5 FNV = 18423472212758727778 / 低 32 位 a2c38c62)。
// ================
/* References:
* saffah_cc_v41_260924, https://duck.ac/submission/120614:
* retained the accepted small-input CDQ engine and its counter-clear policies.
* saffah_codex_6a_agg3, https://duck.ac/submission/120178:
* reused co-locating rank counter arrays under a shared address base.
* saffah_codex_6a_agg3, https://duck.ac/submission/120498:
* reused static suffix-increment masks instead of per-update compare/broadcast.
* Public sources displayed no separate software license notices.
* Idea: Load precomputed exact suffix masks for 16-lane/8-lane counter updates,
* eliminating vector broadcast/compare instructions. Co-locate four counter
* arrays so query/update accesses can share one base register.
* Purpose: Official experiment reducing instruction count in small-input CDQ.
*/
/* References:
* saffah_cc_v41_260924, https://duck.ac/submission/120614:
* retained the accepted small-input CDQ engine and its counter-clear policies.
* saffah_codex_6a_agg3, https://duck.ac/submission/120178:
* reused co-locating rank counter arrays under a shared address base.
* saffah_codex_6a_agg3, https://duck.ac/submission/120498:
* reused static suffix-increment masks instead of per-update compare/broadcast.
* Public sources displayed no separate software license notices.
* Idea: Load precomputed exact suffix masks for 16-lane/8-lane counter updates,
* eliminating vector broadcast/compare instructions. Co-locate four counter
* arrays so query/update accesses can share one base register.
* Purpose: Official experiment reducing instruction count in small-input CDQ.
*/
// 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,tune=sandybridge")
#pragma GCC optimize("O2","unroll-loops","no-inline-functions-called-once","no-ipa-cp","sched-pressure","no-tree-ch","no-ipa-sra","no-tree-vrp")
typedef unsigned u32;
typedef unsigned long long u64;
typedef unsigned char u8;
typedef unsigned short u16;
static const int MAXN = 100001;
static unsigned *g_rootout = 0;
static int g_root_pending = 0;
int g_nz = 0;
#ifndef ZCTHR
#define ZCTHR 16
#endif
#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) & 0xFFFFFu))
#define W_X(v) ((u32)(((v) >> 20) & 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 TIE[(MAXN + 63) / 64 + 8]; // TIE[p] bit = (x[p-1] == x[p])
// H64 and CNT are only live during the BUILD, i.e. before the CDQ ping-pong needs RC[1].
// Aliasing them onto RC[1] removes 1.2 MB of first-touch pages (measured ~0.064 us/KB).
#define H64 ((u64 *)(void *)RC[1])
#define CNT ((u32 *)(void *)(RC[1] + (MAXN + 8)))
#define NGRP ((MAXN + 1023) / 1024 + 8)
struct alignas(64) SmallCounters {
alignas(64) u8 M2TAB[NGRP * 32];
alignas(64) u8 M3TAB[NGRP * 32];
alignas(64) u64 ZB[(MAXN + 63) / 64 + 16];
alignas(64) u16 C1[(MAXN + 63) / 64 + 32];
alignas(64) u16 C2[(MAXN + 1023) / 1024 + 32];
alignas(64) u32 C3[8];
};
static SmallCounters smallct;
#define ZB (smallct.ZB)
#define C1 (smallct.C1)
#define C2 (smallct.C2)
#define C3 (smallct.C3)
#define M2TAB (smallct.M2TAB)
#define M3TAB (smallct.M3TAB)
// ---------- z counter: prefix count over rank domain [0,n) ----------
// LV<=3 COUNTER (n <= 262144, i.e. this row):
// C1[w] (u16) = # inserted ranks in [(w&~15)*64, w*64) -- cumulative in a 16-WORD group
// C2[p] (u16) = # inserted ranks in [(p&~15)*1024, p*1024) -- cumulative in a 16-BLOCK group
// C3[q] (u32) = # inserted ranks in [0, q*16384) -- global cumulative
// count(<T) = C3[T>>14] + C2[T>>10] + C1[T>>6] + popcount(ZB[T>>6] & ((1<<(T&63))-1))
// The query is then FOUR SCALAR LOADS and no vector code at all. The three suffix
// increments in zadd are one aligned 32-byte load/add/store each (windows never partially
// overlap, so store-to-load forwarding is clean).
// bit per rank
// per-word cumulative (group 16 words = 1024 ranks)
// per-1024 cumulative (group 16 blocks = 16384 ranks)
// global cumulative per 16384 ranks (LV<=3)
// LV>=4 fallback (unchanged classic counter, not used on this row)
static u8 ZW1[(MAXN + 63) / 64 + 32];
static u16 ZW2[(MAXN + 1023) / 1024 + 32];
static u16 ZW3[(MAXN + 16383) / 16384 + 32];
static u32 ZW4[(MAXN + 262143) / 262144 + 32];
static const u16 IDX16[16] __attribute__((aligned(32))) = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
static const u32 IDX8[8] __attribute__((aligned(32))) = {0,1,2,3,4,5,6,7};
// add +1 (sgn=+1) / -1 (sgn=-1) to lanes (t0, 15] of the 16-lane u16 group at p
alignas(32) static const u16 PREFIX16[16][16]={{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},{0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1},{0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1},{0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1},{0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1},{0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1},{0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1},{0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1},{0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1},{0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1},{0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1},{0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1},{0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1},{0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1},{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
alignas(32) static const u32 PREFIX8[8][8]={{0,1,1,1,1,1,1,1},{0,0,1,1,1,1,1,1},{0,0,0,1,1,1,1,1},{0,0,0,0,1,1,1,1},{0,0,0,0,0,1,1,1},{0,0,0,0,0,0,1,1},{0,0,0,0,0,0,0,1},{0,0,0,0,0,0,0,0}};
// ---- k09f_: mask rows indexed by the C1 GROUP offset (p*32) so that zadd needs
// no index arithmetic for the C2/C3 masks. Row p holds PREFIX16[p&15] / PREFIX8[p>>4].
// k09m_: inline zero for the counter clears (replaces libc memset, whose ERMS path is
// mostly a callgrind artefact but still carries FORTIFY + call overhead on the small arrays)
static inline void k09k_zr(void *p, size_t n) {
char *q = (char *)p;
__m256i z = _mm256_setzero_si256();
size_t i = 0;
for (; i + 128 <= n; i += 128) {
_mm256_storeu_si256((__m256i *)(void *)(q + i), z);
_mm256_storeu_si256((__m256i *)(void *)(q + i + 32), z);
_mm256_storeu_si256((__m256i *)(void *)(q + i + 64), z);
_mm256_storeu_si256((__m256i *)(void *)(q + i + 96), z);
}
for (; i < n; i += 32) _mm256_storeu_si256((__m256i *)(void *)(q + i), z);
}
#define memset0(p, n) k09k_zr((p), ((n) + 31u) & ~31u)
static constexpr int CounterDomain=100000;
static void mktab(void) {
const int ng = (CounterDomain + 1023) / 1024 + 1;
for (int p = 0; p < ng && p < NGRP; p++) {
__m256i m = _mm256_load_si256((const __m256i *)PREFIX16[p & 15]);
_mm256_store_si256((__m256i *)(void *)(M2TAB + 32 * p), m);
__m256i n = _mm256_load_si256((const __m256i *)PREFIX8[(p >> 4) < 8 ? (p >> 4) : 7]);
_mm256_store_si256((__m256i *)(void *)(M3TAB + 32 * p), n);
}
}
static inline void grp16v(void *p, const void *m, int sgn) {
__m256i x = _mm256_load_si256((const __m256i *)p), y = _mm256_load_si256((const __m256i *)m);
_mm256_store_si256((__m256i *)p, sgn > 0 ? _mm256_add_epi16(x, y) : _mm256_sub_epi16(x, y));
}
static inline void grp8v(void *p, const void *m, int sgn) {
__m256i x = _mm256_load_si256((const __m256i *)p), y = _mm256_load_si256((const __m256i *)m);
_mm256_store_si256((__m256i *)p, sgn > 0 ? _mm256_add_epi32(x, y) : _mm256_sub_epi32(x, y));
}
static inline void grp16b(void *p,u32 t4,int sgn){
__m256i x=_mm256_load_si256((const __m256i*)p),m=_mm256_load_si256((const __m256i*)(const void*)((const char*)PREFIX16+(size_t)t4*8));
_mm256_store_si256((__m256i*)p,sgn>0?_mm256_add_epi16(x,m):_mm256_sub_epi16(x,m));
}
static inline void grp8b(void *p,u32 t4,int sgn){
__m256i x=_mm256_load_si256((const __m256i*)p),m=_mm256_load_si256((const __m256i*)(const void*)((const char*)PREFIX8+(size_t)t4*8));
_mm256_store_si256((__m256i*)p,sgn>0?_mm256_add_epi32(x,m):_mm256_sub_epi32(x,m));
}
template <int LV> static inline void zclear() {
memset0(ZB, (size_t)((CounterDomain + 63) / 64) * 8);
memset0(C1, (size_t)(((CounterDomain + 63) / 64 + 15) / 16) * 32);
memset0(C2, (size_t)(((CounterDomain + 1023) / 1024 + 15) / 16) * 32);
memset0(C3, 32);
if (LV >= 4) { // classic upper levels, used only by the LV>=4 fallback
memset(ZW1, 0, (size_t)((CounterDomain + 63) / 64));
memset(ZW2, 0, (size_t)((CounterDomain + 1023) / 1024) * 2);
memset(ZW3, 0, (size_t)((CounterDomain + 16383) / 16384) * 2);
memset(ZW4, 0, (size_t)((CounterDomain + 262143) / 262144) * 4);
}
}
// Upper LEVELS are tiny; clear them inline (no libc call per node).
static inline void zclear_upper() {
__m128i z = _mm_setzero_si128();
int i2 = (CounterDomain + 1023) / 1024, q2 = (i2 + 7) >> 3;
for (int q = 0; q < q2; q++) _mm_storeu_si128((__m128i *)(void *)(ZW2 + 8 * q), z);
int i3 = (CounterDomain + 16383) / 16384, q3 = (i3 + 7) >> 3;
for (int q = 0; q < q3; q++) _mm_storeu_si128((__m128i *)(void *)(ZW3 + 8 * q), z);
int i4 = (CounterDomain + 262143) / 262144, q4 = (i4 + 3) >> 2;
for (int q = 0; q < q4; q++) _mm_storeu_si128((__m128i *)(void *)(ZW4 + 4 * q), z);
int i1 = (CounterDomain + 63) / 64, q1 = (i1 + 15) >> 4;
for (int q = 0; q < q1; q++) _mm_storeu_si128((__m128i *)(void *)(ZW1 + 16 * q), z);
}
// Touched-only clear: the ZB word (and, at LV<=3, the C1/C2 GROUPS) of the ranks this node
// inserted. ⚠ At LV>=4 the classic ZW1/ZW2/ZW3 levels are live and MUST be cleared here too
// -- clearing only ZB/C1/C2 would leave them stale.
template <int LV> static inline void zclear_touched(int l, int aIns, const u64 *S) {
__m256i z = _mm256_setzero_si256();
for (int k = l; k < aIns; k++) {
u32 r = W_R(S[2 * k + 1]);
ZB[r >> 6] = 0;
if (LV <= 3) {
_mm256_store_si256((__m256i *)(void *)(C1 + ((r >> 6) & ~15u)), z);
_mm256_store_si256((__m256i *)(void *)(C2 + ((r >> 10) & ~15u)), z);
}
}
if (LV <= 3) _mm256_store_si256((__m256i *)(void *)C3, z);
else zclear_upper();
}
// ---- CHEAP CLEAR ------------------------------------------------------------------
// Two facts, both from measurement (custom_test n=1e5; 1.094M zadds over 4094 nodes):
// * C2 has only (n>>10) 16-lane groups (~7 for n=1e5) and C3 is ONE 8-lane vector, so
// one C2/C3 store per inserted rank was ~85% redundant;
// * the FULL clear memsets ZB (12.5 KB ~= 390 store-slots) however few ranks the node
// inserted; below ~400 inserts the per-rank ZB clear is the cheaper one.
// Zeroing MORE than the node dirtied is always correct -- an already-zero entry stays
// zero, and after the clear the counter reads 0 for every T either way.
#ifndef C1GRP
#define C1GRP 98
#endif
#ifndef ZBTHR
#define ZBTHR 400
#endif
static inline void zclear_C23() {
__m256i z = _mm256_setzero_si256();
int i2 = (CounterDomain + 1023) / 1024, q2 = (i2 + 15) >> 4;
for (int q = 0; q < q2; q++) _mm256_store_si256((__m256i *)(void *)(C2 + 16 * q), z);
_mm256_store_si256((__m256i *)(void *)C3, z);
}
template <int LV> static inline void zclear_cheap(int l, int aIns, const u64 *S) {
if (LV <= 3) {
if (aIns - l >= C1GRP) {
for (int k = l; k < aIns; k++) ZB[W_R(S[2 * k + 1]) >> 6] = 0;
memset0(C1, (size_t)(((CounterDomain + 63) / 64 + 15) / 16) * 32);
} else {
__m256i z = _mm256_setzero_si256();
for (int k = l; k < aIns; k++) {
u32 r = W_R(S[2 * k + 1]);
ZB[r >> 6] = 0;
_mm256_store_si256((__m256i *)(void *)(C1 + ((r >> 6) & ~15u)), z);
}
}
zclear_C23();
} else {
for (int k = l; k < aIns; k++) ZB[W_R(S[2 * k + 1]) >> 6] = 0;
zclear_upper();
}
}
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 void zadd(u32 r) {
if (LV <= 3) {
const u32 g1 = (r >> 5) & ~31u; // p*32 : C1 group byte offset == table row offset
const u32 g2 = (g1 >> 4) & ~31u; // (p/16)*32 : C2 group byte offset
ZB[r >> 6] |= 1ull << (r & 63);
grp16b((char*)C1 + g1, (r >> 4) & 60u, +1);
grp16v((char*)C2 + g2, M2TAB + g1, +1);
grp8v ((char*)C3, M3TAB + g1, +1);
} else { ZB[r>>6] |= 1ull<<(r&63); ZW1[r >> 6]++; ZW2[r >> 10]++; ZW3[r >> 14]++; ZW4[r >> 18]++; }
}
template <int LV> static inline void zsub(u32 r) {
if (LV <= 3) {
const u32 g1 = (r >> 5) & ~31u;
const u32 g2 = (g1 >> 4) & ~31u;
ZB[r >> 6] &= ~(1ull << (r & 63));
grp16b((char*)C1 + g1, (r >> 4) & 60u, -1);
grp16v((char*)C2 + g2, M2TAB + g1, -1);
grp8v ((char*)C3, M3TAB + g1, -1);
} else { ZB[r>>6] &= ~(1ull<<(r&63)); ZW1[r >> 6]--; ZW2[r >> 10]--; ZW3[r >> 14]--; ZW4[r >> 18]--; }
}
static inline u32 hsum256(__m256i s) {
__m128i lo = _mm256_castsi256_si128(s), hi = _mm256_extracti128_si256(s, 1);
__m128i t = _mm_add_epi32(lo, hi);
t = _mm_add_epi32(t, _mm_shuffle_epi32(t, _MM_SHUFFLE(1, 0, 3, 2)));
t = _mm_add_epi32(t, _mm_shuffle_epi32(t, _MM_SHUFFLE(2, 3, 0, 1)));
return (u32)_mm_cvtsi128_si32(t);
}
template <int LV> static inline u32 zquery(u32 T) {
if (LV <= 3) {
// FOUR SCALAR LOADS, NO VECTOR CODE: C3[T>>14] + C2[T>>10] + C1[T>>6] + bits
u32 w = T >> 6;
u32 s = (u32)C3[T >> 14] + (u32)C2[T >> 10] + (u32)C1[w];
return s + (u32)__builtin_popcountll(_bzhi_u64(ZB[w], T & 63));
}
u32 k4 = T >> 18, k3 = (T >> 14) & 15, k2 = (T >> 10) & 15, k1 = (T >> 6) & 15, rem = T & 63;
__m256i acc = _mm256_setzero_si256();
if (LV >= 4) acc = _mm256_and_si256(_mm256_loadu_si256((const __m256i *)ZW4),
_mm256_cmpgt_epi32(_mm256_set1_epi32((int)k4), _mm256_setr_epi32(0,1,2,3,4,5,6,7)));
acc = _mm256_add_epi32(acc, _mm256_madd_epi16(_mm256_and_si256(
_mm256_loadu_si256((const __m256i *)(ZW3 + (k4 << 4))),
_mm256_cmpgt_epi16(_mm256_set1_epi16((short)k3), mkI16())), mkOne16()));
acc = _mm256_add_epi32(acc, _mm256_madd_epi16(_mm256_and_si256(
_mm256_loadu_si256((const __m256i *)(ZW2 + ((T >> 14) << 4))),
_mm256_cmpgt_epi16(_mm256_set1_epi16((short)k2), mkI16())), mkOne16()));
__m128i s8 = _mm_sad_epu8(_mm_and_si128(
_mm_loadu_si128((const __m128i *)(ZW1 + ((T >> 10) << 4))),
_mm_cmpgt_epi8(_mm_set1_epi8((char)k1), mkI8())), _mm_setzero_si128());
u32 s = hsum256(acc) + (u32)_mm_cvtsi128_si32(s8) + (u32)(_mm_extract_epi16(s8, 4) & 0xFFFF);
s += (u32)__builtin_popcountll(_bzhi_u64(ZB[T >> 6], rem));
return s;
}
#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;
}
// [r2e_] root-only fused y-merge: identical decisions/counters to node_fused, but each
// finished record goes straight to out[] (the caller's array) instead of the RC buffer,
// so neither the record stores nor the whole post pass are needed.
template <int LV> static void node_fused_root(int l, int m, int r, int src) {
u64 *S = RC[src];
int a = l, b = m;
if (a < m && b < r) {
const u64 *pa = S + 2 * a, *pb = S + 2 * b;
const u64 *const pae = S + 2 * m, *const pbe = S + 2 * r;
u64 w0a = pa[0], w1a = pa[1];
u64 w0b = pb[0], w1b = pb[1];
for (;;) {
if (w0b <= (w0a | 0xFFFFFFFFFFull)) { // right first on equal y (strict)
w0b += zquery<LV>((u32)(w1b >> 40));
g_rootout[W_ORIG(w0b)] = W_A(w0b); pb += 2;
if (pb >= pbe) break;
w0b = pb[0]; w1b = pb[1];
} else {
zadd<LV>(W_R(w1a));
g_rootout[W_ORIG(w0a)] = W_A(w0a); pa += 2;
if (pa >= pae) break;
w0a = pa[0]; w1a = pa[1];
}
}
a = (int)((pa - S) >> 1); b = (int)((pb - S) >> 1);
}
while (b < r) {
u64 w0b = S[2 * b] + zquery<LV>((u32)(S[2 * b + 1] >> 40));
g_rootout[W_ORIG(w0b)] = W_A(w0b); b++;
}
while (a < m) { u64 w0 = S[2 * a]; g_rootout[W_ORIG(w0)] = W_A(w0); a++; }
}
// 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, t = l;
if (a < m && b < r) {
const u64 *pa = S + 2 * a, *pb = S + 2 * b; u64 *pd = D + 2 * l;
const u64 *const pae = S + 2 * m, *const pbe = S + 2 * r;
u64 w0a = pa[0], w1a = pa[1];
u64 w0b = pb[0], w1b = pb[1];
for (;;) {
{ const u64 na0 = pa[2], na1 = pa[3], nb0 = pb[2], nb1 = pb[3];
if (w0b <= (w0a | 0xFFFFFFFFFFull)) { // right first on equal y (strict):
// (w0b>>40)<=(w0a>>40) <=> w0b <= (w0a|0xFFFFFFFFFF), the largest u64 with y==y_a
w0b += zquery<LV>((u32)(w1b >> 40));
pd[0] = w0b; pd[1] = w1b; pd += 2; pb += 2;
if (pb >= pbe) break;
w0b = nb0; w1b = nb1;
} else {
zadd<LV>(W_R(w1a));
pd[0] = w0a; pd[1] = w1a; pd += 2; pa += 2;
if (pa >= pae) break;
w0a = na0; w1a = na1;
} }
}
a = (int)((pa - S) >> 1); b = (int)((pb - S) >> 1); t = (int)((pd - D) >> 1);
}
int aIns = a;
while (b < r) {
u64 w0b = S[2 * b], w1b = S[2 * b + 1];
w0b += zquery<LV>((u32)(w1b >> 40));
D[2 * t] = w0b; D[2 * t + 1] = w1b; b++; t++;
}
while (a < m) { D[2 * t] = S[2 * a]; D[2 * t + 1] = S[2 * a + 1]; a++; t++; }
// full zclear ~= 497 vector stores + 4 memset calls; touched-clear ~= 3 stores per insert.
if (aIns - l >= ZBTHR) zclear<LV>();
else if (r - l >= ZCTHR) zclear_cheap<LV>(l, aIns, S);
else for (int k = l; k < aIns; k++) zsub<LV>(W_R(S[2 * k + 1]));
}
// 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;
{ const u64 *pa = S + 2 * a, *pb = S + 2 * b; u64 *pd = D + 2 * t;
const u64 *const pae = S + 2 * m, *const pbe = S + 2 * r;
while (pa < pae && pb < pbe) {
const u64 *ps = ((*pa >> 40) <= (*pb >> 40)) ? pa : pb;
pd[0] = ps[0]; pd[1] = ps[1]; pd += 2;
if (ps == pa) pa += 2; else pb += 2;
}
a = (int)((pa - S) >> 1); b = (int)((pb - S) >> 1); t = (int)((pd - D) >> 1);
}
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
alignas(32) static const unsigned TAIL4MASK[25][8]={
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0xffffffffu,0,0,0,0,0,0,0},
{0xffffffffu,0xffffffffu,0,0,0,0,0,0},
{0xffffffffu,0xffffffffu,0xffffffffu,0,0,0,0,0},
{0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0,0,0,0},
{0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0,0,0},
{0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0,0},
{0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0},
{0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu},
{0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu},
{0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu},
{0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu},
{0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu},
{0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu},
{0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu},
{0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu},
{0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu,0xffffffffu}
};
struct alignas(64) LeafScratch {
alignas(32) u32 lex[LSCR + 16]; alignas(32) u32 ley[LSCR + 16]; alignas(32) u32 ler[LSCR + 16];
alignas(32) u64 lkey[LSCR + 16]; alignas(32) u64 ltmp[2 * (LSCR + 16)];
alignas(32) u32 lk[256];
alignas(32) u32 lyk[LSCR + 16]; alignas(32) u32 lxq[LSCR + 16];
alignas(32) u32 lzq[LSCR + 16]; alignas(32) u32 ltq[LSCR + 16]; alignas(32) u32 lst[LSCR + 16];
};
static LeafScratch lsc;
#define lex (lsc.lex)
#define ley (lsc.ley)
#define ler (lsc.ler)
#define lkey (lsc.lkey)
#define ltmp (lsc.ltmp)
#define lk (lsc.lk)
#define lyk (lsc.lyk)
#define lxq (lsc.lxq)
#define lzq (lsc.lzq)
#define ltq (lsc.ltq)
#define lst (lsc.lst)
// ---- generated AVX2 bitonic sort of 64 u32 keys (keys in r[0..7]) ----
static inline void bs64(__m256i *r) {
{ __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[0]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x66); }
{ __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[1]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x66); }
{ __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[2]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x66); }
{ __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[3]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x66); }
{ __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[4]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x66); }
{ __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[5]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x66); }
{ __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[6]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x66); }
{ __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[7]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x66); }
{ __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[0]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x3C); }
{ __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[1]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x3C); }
{ __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[2]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x3C); }
{ __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[3]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x3C); }
{ __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[4]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x3C); }
{ __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[5]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x3C); }
{ __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[6]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x3C); }
{ __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[7]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x3C); }
{ __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[0]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x5A); }
{ __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[1]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x5A); }
{ __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[2]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x5A); }
{ __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[3]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x5A); }
{ __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[4]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x5A); }
{ __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[5]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x5A); }
{ __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[6]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x5A); }
{ __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[7]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x5A); }
{ __m256i A=r[0]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[0]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[1]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[1]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x0F); }
{ __m256i A=r[2]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[2]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[3]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[3]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x0F); }
{ __m256i A=r[4]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[4]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[5]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[5]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x0F); }
{ __m256i A=r[6]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[6]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[7]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[7]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x0F); }
{ __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[0]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[1]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x33); }
{ __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[2]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[3]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x33); }
{ __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[4]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[5]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x33); }
{ __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[6]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[7]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x33); }
{ __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[0]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
{ __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[1]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x55); }
{ __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[2]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
{ __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[3]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x55); }
{ __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[4]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
{ __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[5]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x55); }
{ __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[6]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
{ __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[7]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x55); }
{ __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_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[1]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[1]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[2]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[2]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x0F); }
{ __m256i A=r[3]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[3]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x0F); }
{ __m256i A=r[4]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[4]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[5]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[5]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[6]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[6]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x0F); }
{ __m256i A=r[7]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[7]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x0F); }
{ __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[0]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[1]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[2]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x33); }
{ __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[3]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x33); }
{ __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[4]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[5]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[6]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x33); }
{ __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[7]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x33); }
{ __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[0]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
{ __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[1]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
{ __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[2]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x55); }
{ __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[3]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x55); }
{ __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[4]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
{ __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[5]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
{ __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[6]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x55); }
{ __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[7]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x55); }
{ __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_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[1]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[1]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[2]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[2]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[3]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[3]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[4]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[4]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x0F); }
{ __m256i A=r[5]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[5]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x0F); }
{ __m256i A=r[6]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[6]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x0F); }
{ __m256i A=r[7]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[7]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x0F); }
{ __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[0]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[1]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[2]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[3]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[4]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x33); }
{ __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[5]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x33); }
{ __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[6]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x33); }
{ __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[7]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x33); }
{ __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[0]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
{ __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[1]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
{ __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[2]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
{ __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[3]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
{ __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[4]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x55); }
{ __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[5]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x55); }
{ __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[6]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x55); }
{ __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[7]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0x55); }
{ __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_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[1]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[1]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[2]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[2]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[3]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[3]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[4]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[4]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[5]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[5]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[6]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[6]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[7]; __m256i T=_mm256_permute4x64_epi64(A,0x4E); r[7]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xF0); }
{ __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[0]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[1]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[2]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[3]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[4]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[5]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[6]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0x4E); r[7]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xCC); }
{ __m256i A=r[0]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[0]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
{ __m256i A=r[1]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[1]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
{ __m256i A=r[2]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[2]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
{ __m256i A=r[3]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[3]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
{ __m256i A=r[4]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[4]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
{ __m256i A=r[5]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[5]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
{ __m256i A=r[6]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[6]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
{ __m256i A=r[7]; __m256i T=_mm256_shuffle_epi32(A,0xB1); r[7]=_mm256_blend_epi32(_mm256_min_epu32(A,T),_mm256_max_epu32(A,T),0xAA); }
}
// ---- 128-key BITONIC MERGE (branch-free, fixed network) ---------------------
// In: k[0..63] ascending and k[64..127] ascending. Out: k[0..127] ascending.
static inline void bm128(u32 *k) {
const __m256i BM_IDX64 = _mm256_setr_epi32(7,6,5,4,3,2,1,0);
{ // reverse the top half
__m256i t[8];
for (int q = 0; q < 8; q++) t[q] = _mm256_permutevar8x32_epi32(
_mm256_load_si256((const __m256i *)(k + 64 + 8 * (7 - q))), BM_IDX64);
for (int q = 0; q < 8; q++) _mm256_store_si256((__m256i *)(k + 64 + 8 * q), t[q]);
}
for (int d = 64; d >= 8; d >>= 1) {
for (int base = 0; base < 128; base += 2 * d)
for (int j = 0; j < d; j += 8) {
__m256i a = _mm256_load_si256((const __m256i *)(k + base + j));
__m256i b = _mm256_load_si256((const __m256i *)(k + base + j + d));
_mm256_store_si256((__m256i *)(k + base + j), _mm256_min_epu32(a, b));
_mm256_store_si256((__m256i *)(k + base + j + d), _mm256_max_epu32(a, b));
}
}
for (int d = 4; d >= 1; d >>= 1) {
__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 < 128; base += 8) {
__m256i a = _mm256_load_si256((const __m256i *)(k + base));
__m256i p = _mm256_permutevar8x32_epi32(a, idx);
__m256i lo = _mm256_min_epu32(a, p), hi = _mm256_max_epu32(a, p);
_mm256_store_si256((__m256i *)(k + base), _mm256_blendv_epi8(lo, hi, bsel));
}
}
}
// ---- 256-key BITONIC MERGE: in k[0..127] and k[128..255] each ascending ----
static inline void bm256(u32 *k) {
const __m256i BM_IDX64 = _mm256_setr_epi32(7,6,5,4,3,2,1,0);
{ __m256i t[16];
for (int q = 0; q < 16; q++) t[q] = _mm256_permutevar8x32_epi32(
_mm256_load_si256((const __m256i *)(k + 128 + 8 * (15 - q))), BM_IDX64);
for (int q = 0; q < 16; q++) _mm256_store_si256((__m256i *)(k + 128 + 8 * q), t[q]);
}
for (int d = 128; d >= 8; d >>= 1) {
for (int base = 0; base < 256; base += 2 * d)
for (int j = 0; j < d; j += 8) {
__m256i a = _mm256_load_si256((const __m256i *)(k + base + j));
__m256i b = _mm256_load_si256((const __m256i *)(k + base + j + d));
_mm256_store_si256((__m256i *)(k + base + j), _mm256_min_epu32(a, b));
_mm256_store_si256((__m256i *)(k + base + j + d), _mm256_max_epu32(a, b));
}
}
for (int d = 4; d >= 1; d >>= 1) {
__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 < 256; base += 8) {
__m256i a = _mm256_load_si256((const __m256i *)(k + base));
__m256i p = _mm256_permutevar8x32_epi32(a, idx);
__m256i lo = _mm256_min_epu32(a, p), hi = _mm256_max_epu32(a, p);
_mm256_store_si256((__m256i *)(k + base), _mm256_blendv_epi8(lo, hi, bsel));
}
}
}
static inline __m256i packed_leaf_test(__m256i q,__m256i v){
const __m256i guards=_mm256_set1_epi32((int)0x80020000u);
__m256i result;
asm("vpsubd %2,%1,%0\n\tvpand %3,%0,%0\n\tvpcmpeqd %3,%0,%0"
: "=&x"(result) : "x"(q),"x"(v),"x"(guards));
return result;
}
static void packed_leaf_count(int sn){
int g=0,q=1;
for(;q+5<sn;q+=6){
if((lk[q]>>8)!=(lk[q-1]>>8))g=q;
const int G0=g;
const int G1=((lk[q+1]>>8)!=(lk[q+0]>>8))?q+1:G0;
const int G2=((lk[q+2]>>8)!=(lk[q+1]>>8))?q+2:G1;
const int G3=((lk[q+3]>>8)!=(lk[q+2]>>8))?q+3:G2;
const int G4=((lk[q+4]>>8)!=(lk[q+3]>>8))?q+4:G3;
const int G5=((lk[q+5]>>8)!=(lk[q+4]>>8))?q+5:G4;
const __m256i t0=_mm256_set1_epi32((int)ltq[q+0]);
__m256i a0=_mm256_setzero_si256();
const __m256i t1=_mm256_set1_epi32((int)ltq[q+1]);
__m256i a1=_mm256_setzero_si256();
const __m256i t2=_mm256_set1_epi32((int)ltq[q+2]);
__m256i a2=_mm256_setzero_si256();
const __m256i t3=_mm256_set1_epi32((int)ltq[q+3]);
__m256i a3=_mm256_setzero_si256();
const __m256i t4=_mm256_set1_epi32((int)ltq[q+4]);
__m256i a4=_mm256_setzero_si256();
const __m256i t5=_mm256_set1_epi32((int)ltq[q+5]);
__m256i a5=_mm256_setzero_si256();
int k=0;
for(;k+8<=G0;k+=8){
const __m256i v=_mm256_loadu_si256((const __m256i*)(lxq+k));
a0=_mm256_sub_epi32(a0,packed_leaf_test(t0,v));
a1=_mm256_sub_epi32(a1,packed_leaf_test(t1,v));
a2=_mm256_sub_epi32(a2,packed_leaf_test(t2,v));
a3=_mm256_sub_epi32(a3,packed_leaf_test(t3,v));
a4=_mm256_sub_epi32(a4,packed_leaf_test(t4,v));
a5=_mm256_sub_epi32(a5,packed_leaf_test(t5,v));
}
if(G5-G0<=5){
for(;k<G5;k+=8){
const __m256i v=_mm256_loadu_si256((const __m256i*)(lxq+k));
a0=_mm256_sub_epi32(a0,_mm256_and_si256(packed_leaf_test(t0,v),_mm256_load_si256((const __m256i*)TAIL4MASK[8+G0-k])));
a1=_mm256_sub_epi32(a1,_mm256_and_si256(packed_leaf_test(t1,v),_mm256_load_si256((const __m256i*)TAIL4MASK[8+G1-k])));
a2=_mm256_sub_epi32(a2,_mm256_and_si256(packed_leaf_test(t2,v),_mm256_load_si256((const __m256i*)TAIL4MASK[8+G2-k])));
a3=_mm256_sub_epi32(a3,_mm256_and_si256(packed_leaf_test(t3,v),_mm256_load_si256((const __m256i*)TAIL4MASK[8+G3-k])));
a4=_mm256_sub_epi32(a4,_mm256_and_si256(packed_leaf_test(t4,v),_mm256_load_si256((const __m256i*)TAIL4MASK[8+G4-k])));
a5=_mm256_sub_epi32(a5,_mm256_and_si256(packed_leaf_test(t5,v),_mm256_load_si256((const __m256i*)TAIL4MASK[8+G5-k])));
}}else{
for(int j=k;j<G0;j+=8){
a0=_mm256_sub_epi32(a0,_mm256_and_si256(packed_leaf_test(t0,_mm256_loadu_si256((const __m256i*)(lxq+j))),_mm256_load_si256((const __m256i*)TAIL4MASK[8+((G0-j<8)?G0-j:8)])));
}
for(int j=k;j<G1;j+=8){
a1=_mm256_sub_epi32(a1,_mm256_and_si256(packed_leaf_test(t1,_mm256_loadu_si256((const __m256i*)(lxq+j))),_mm256_load_si256((const __m256i*)TAIL4MASK[8+((G1-j<8)?G1-j:8)])));
}
for(int j=k;j<G2;j+=8){
a2=_mm256_sub_epi32(a2,_mm256_and_si256(packed_leaf_test(t2,_mm256_loadu_si256((const __m256i*)(lxq+j))),_mm256_load_si256((const __m256i*)TAIL4MASK[8+((G2-j<8)?G2-j:8)])));
}
for(int j=k;j<G3;j+=8){
a3=_mm256_sub_epi32(a3,_mm256_and_si256(packed_leaf_test(t3,_mm256_loadu_si256((const __m256i*)(lxq+j))),_mm256_load_si256((const __m256i*)TAIL4MASK[8+((G3-j<8)?G3-j:8)])));
}
for(int j=k;j<G4;j+=8){
a4=_mm256_sub_epi32(a4,_mm256_and_si256(packed_leaf_test(t4,_mm256_loadu_si256((const __m256i*)(lxq+j))),_mm256_load_si256((const __m256i*)TAIL4MASK[8+((G4-j<8)?G4-j:8)])));
}
for(int j=k;j<G5;j+=8){
a5=_mm256_sub_epi32(a5,_mm256_and_si256(packed_leaf_test(t5,_mm256_loadu_si256((const __m256i*)(lxq+j))),_mm256_load_si256((const __m256i*)TAIL4MASK[8+((G5-j<8)?G5-j:8)])));
}
}
const __m256i h01=_mm256_hadd_epi32(a0,a1),h23=_mm256_hadd_epi32(a2,a3),h45=_mm256_hadd_epi32(a4,a5);
const __m256i h03=_mm256_hadd_epi32(h01,h23),h4z=_mm256_hadd_epi32(h45,_mm256_setzero_si256());
const __m128i r03=_mm_add_epi32(_mm256_castsi256_si128(h03),_mm256_extracti128_si256(h03,1));
const __m128i r45=_mm_add_epi32(_mm256_castsi256_si128(h4z),_mm256_extracti128_si256(h4z,1));
ltmp[2*(q+0)]+=(u32)_mm_extract_epi32(r03,0);
ltmp[2*(q+1)]+=(u32)_mm_extract_epi32(r03,1);
ltmp[2*(q+2)]+=(u32)_mm_extract_epi32(r03,2);
ltmp[2*(q+3)]+=(u32)_mm_extract_epi32(r03,3);
ltmp[2*(q+4)]+=(u32)_mm_extract_epi32(r45,0);
ltmp[2*(q+5)]+=(u32)_mm_extract_epi32(r45,1);
g=G5;
}
for(;q<sn;q++){
if((lk[q]>>8)!=(lk[q-1]>>8))g=q;
__m256i tq=_mm256_set1_epi32((int)ltq[q]),acc=_mm256_setzero_si256();int k=0;
for(;k+8<=g;k+=8)acc=_mm256_sub_epi32(acc,packed_leaf_test(tq,_mm256_loadu_si256((const __m256i*)(lxq+k))));
__m128i h=_mm_add_epi32(_mm256_castsi256_si128(acc),_mm256_extracti128_si256(acc,1));
h=_mm_add_epi32(h,_mm_shuffle_epi32(h,0x4e));h=_mm_add_epi32(h,_mm_shuffle_epi32(h,0xb1));
u32 c=(u32)_mm_cvtsi128_si32(h);
if(k<g){__m256i v=packed_leaf_test(tq,_mm256_loadu_si256((const __m256i*)(lxq+k)));c+=(u32)__builtin_popcount(_bzhi_u32((u32)_mm256_movemask_ps(_mm256_castsi256_ps(v)),g-k));}
ltmp[2*q]+=c;
}
}
static int cdq_leaf256(int l, int r, int in) {
u64 *S = RC[in];
const int sn = r - l;
if (sn <= 64) {
for (int k = 0; k < sn; k++) lk[k] = (u32)(S[2 * (l + k)] >> 40) << 8 | (u32)k;
for (int k = sn; k < 64; k++) lk[k] = 0xFFFFFFFFu;
{ __m256i r0[8];
for (int q = 0; q < 8; q++) r0[q] = _mm256_load_si256((const __m256i *)(lk + 8 * q));
bs64(r0);
for (int q = 0; q < 8; q++) _mm256_store_si256((__m256i *)(lk + 8 * q), r0[q]); }
} else if (sn <= 128) {
for (int k = 0; k < sn; k++) lk[k] = (u32)(S[2 * (l + k)] >> 40) << 8 | (u32)k;
for (int k = sn; k < 128; k++) lk[k] = 0xFFFFFFFFu;
{ __m256i r0[8];
for (int q = 0; q < 8; q++) r0[q] = _mm256_load_si256((const __m256i *)(lk + 8 * q));
bs64(r0);
for (int q = 0; q < 8; q++) _mm256_store_si256((__m256i *)(lk + 8 * q), r0[q]);
for (int q = 0; q < 8; q++) r0[q] = _mm256_load_si256((const __m256i *)(lk + 64 + 8 * q));
bs64(r0);
for (int q = 0; q < 8; q++) _mm256_store_si256((__m256i *)(lk + 64 + 8 * q), r0[q]); }
bm128(lk);
} else {
for (int k = 0; k < sn; k++) lk[k] = (u32)(S[2 * (l + k)] >> 40) << 8 | (u32)k;
for (int k = sn; k < 256; k++) lk[k] = 0xFFFFFFFFu;
{ __m256i r0[8];
for (int q = 0; q < 8; q++) r0[q] = _mm256_load_si256((const __m256i *)(lk + 8 * q));
bs64(r0);
for (int q = 0; q < 8; q++) _mm256_store_si256((__m256i *)(lk + 8 * q), r0[q]);
for (int q = 0; q < 8; q++) r0[q] = _mm256_load_si256((const __m256i *)(lk + 64 + 8 * q));
bs64(r0);
for (int q = 0; q < 8; q++) _mm256_store_si256((__m256i *)(lk + 64 + 8 * q), r0[q]);
for (int q = 0; q < 8; q++) r0[q] = _mm256_load_si256((const __m256i *)(lk + 128 + 8 * q));
bs64(r0);
for (int q = 0; q < 8; q++) _mm256_store_si256((__m256i *)(lk + 128 + 8 * q), r0[q]);
for (int q = 0; q < 8; q++) r0[q] = _mm256_load_si256((const __m256i *)(lk + 192 + 8 * q));
bs64(r0);
for (int q = 0; q < 8; q++) _mm256_store_si256((__m256i *)(lk + 192 + 8 * q), r0[q]); }
bm128(lk); bm128(lk + 128); bm256(lk);
}
const u32 xbase=W_X(S[2*l+1]);
if(W_X(S[2*(r-1)+1])-xbase<8192u && g_nz<131072){
for(int q=0;q<sn;q++){
int sr=(int)(lk[q]&255u);u64 w0=S[2*(l+sr)],w1=S[2*(l+sr)+1];
ltmp[2*q]=w0;ltmp[2*q+1]=w1;
u32 xb=(W_X(w1)-xbase)<<18;
lxq[q]=xb|W_R(w1);
ltq[q]=((xb|W_T(w1))|0x80020000u)-0x40001u;
}
packed_leaf_count(sn);
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;
}
for (int q = 0; q < sn; q++) {
const int sr = (int)(lk[q] & 255u);
u64 w0 = S[2 * (l + sr)], w1 = S[2 * (l + sr) + 1];
ltmp[2 * q] = w0; ltmp[2 * q + 1] = w1;
lxq[q] = (u32)((w1 >> 20) & 0xFFFFFu);
lzq[q] = (u32)(w1 & 0xFFFFFu);
ltq[q] = (u32)(w1 >> 40);
}
int g=0,q=1;
{ // 4-wide: shared loads over the common y-prefix
const auto red=[]( __m256i v)->u32{
__m128i s=_mm_add_epi32(_mm256_castsi256_si128(v),_mm256_extracti128_si256(v,1));
s=_mm_add_epi32(s,_mm_shuffle_epi32(s,0x4e));s=_mm_add_epi32(s,_mm_shuffle_epi32(s,0xb1));return (u32)_mm_cvtsi128_si32(s); };
const auto tl=[&](const __m256i xj,const __m256i tj,int k,int n)->u32{
__m256i c=_mm256_and_si256(_mm256_cmpgt_epi32(xj,_mm256_loadu_si256((const __m256i*)(lxq+k))),_mm256_cmpgt_epi32(tj,_mm256_loadu_si256((const __m256i*)(lzq+k))));
return (u32)__builtin_popcount(_bzhi_u32((u32)_mm256_movemask_ps(_mm256_castsi256_ps(c)),(u32)n)); };
for(;q+3<sn;q+=4){
if((lk[q]>>8)!=(lk[q-1]>>8))g=q;
const int G0=g;
const int G1=((lk[q+1]>>8)!=(lk[q]>>8))?q+1:G0;
const int G2=((lk[q+2]>>8)!=(lk[q+1]>>8))?q+2:G1;
const int G3=((lk[q+3]>>8)!=(lk[q+2]>>8))?q+3:G2;
const __m256i x0=_mm256_set1_epi32((int)lxq[q ]),t0=_mm256_set1_epi32((int)ltq[q ]);
const __m256i x1=_mm256_set1_epi32((int)lxq[q+1]),t1=_mm256_set1_epi32((int)ltq[q+1]);
const __m256i x2=_mm256_set1_epi32((int)lxq[q+2]),t2=_mm256_set1_epi32((int)ltq[q+2]);
const __m256i x3=_mm256_set1_epi32((int)lxq[q+3]),t3=_mm256_set1_epi32((int)ltq[q+3]);
__m256i a0=_mm256_setzero_si256(),a1=a0,a2=a0,a3=a0; int k=0;
for(;k+8<=G0;k+=8){
const __m256i vx=_mm256_loadu_si256((const __m256i*)(lxq+k));
const __m256i vz=_mm256_loadu_si256((const __m256i*)(lzq+k));
a0=_mm256_sub_epi32(a0,_mm256_and_si256(_mm256_cmpgt_epi32(x0,vx),_mm256_cmpgt_epi32(t0,vz)));
a1=_mm256_sub_epi32(a1,_mm256_and_si256(_mm256_cmpgt_epi32(x1,vx),_mm256_cmpgt_epi32(t1,vz)));
a2=_mm256_sub_epi32(a2,_mm256_and_si256(_mm256_cmpgt_epi32(x2,vx),_mm256_cmpgt_epi32(t2,vz)));
a3=_mm256_sub_epi32(a3,_mm256_and_si256(_mm256_cmpgt_epi32(x3,vx),_mm256_cmpgt_epi32(t3,vz)));
}
u32 c0=0,c1=0,c2=0,c3=0;
if(G3-G0<=3){
for(;k<G3;k+=8){
const __m256i vx=_mm256_loadu_si256((const __m256i*)(lxq+k));
const __m256i vz=_mm256_loadu_si256((const __m256i*)(lzq+k));
a0=_mm256_sub_epi32(a0,_mm256_and_si256(_mm256_and_si256(_mm256_cmpgt_epi32(x0,vx),_mm256_cmpgt_epi32(t0,vz)),_mm256_load_si256((const __m256i*)TAIL4MASK[8+G0-k])));
a1=_mm256_sub_epi32(a1,_mm256_and_si256(_mm256_and_si256(_mm256_cmpgt_epi32(x1,vx),_mm256_cmpgt_epi32(t1,vz)),_mm256_load_si256((const __m256i*)TAIL4MASK[8+G1-k])));
a2=_mm256_sub_epi32(a2,_mm256_and_si256(_mm256_and_si256(_mm256_cmpgt_epi32(x2,vx),_mm256_cmpgt_epi32(t2,vz)),_mm256_load_si256((const __m256i*)TAIL4MASK[8+G2-k])));
a3=_mm256_sub_epi32(a3,_mm256_and_si256(_mm256_and_si256(_mm256_cmpgt_epi32(x3,vx),_mm256_cmpgt_epi32(t3,vz)),_mm256_load_si256((const __m256i*)TAIL4MASK[8+G3-k])));
}
}else{
c0=k<G0?tl(x0,t0,k,G0-k):0;
for(;k+8<=G1;k+=8){ const __m256i vx=_mm256_loadu_si256((const __m256i*)(lxq+k));
const __m256i vz=_mm256_loadu_si256((const __m256i*)(lzq+k));
a1=_mm256_sub_epi32(a1,_mm256_and_si256(_mm256_cmpgt_epi32(x1,vx),_mm256_cmpgt_epi32(t1,vz)));
a2=_mm256_sub_epi32(a2,_mm256_and_si256(_mm256_cmpgt_epi32(x2,vx),_mm256_cmpgt_epi32(t2,vz)));
a3=_mm256_sub_epi32(a3,_mm256_and_si256(_mm256_cmpgt_epi32(x3,vx),_mm256_cmpgt_epi32(t3,vz))); }
c1=k<G1?tl(x1,t1,k,G1-k):0;
for(;k+8<=G2;k+=8){ const __m256i vx=_mm256_loadu_si256((const __m256i*)(lxq+k));
const __m256i vz=_mm256_loadu_si256((const __m256i*)(lzq+k));
a2=_mm256_sub_epi32(a2,_mm256_and_si256(_mm256_cmpgt_epi32(x2,vx),_mm256_cmpgt_epi32(t2,vz)));
a3=_mm256_sub_epi32(a3,_mm256_and_si256(_mm256_cmpgt_epi32(x3,vx),_mm256_cmpgt_epi32(t3,vz))); }
c2=k<G2?tl(x2,t2,k,G2-k):0;
for(;k+8<=G3;k+=8){ const __m256i vx=_mm256_loadu_si256((const __m256i*)(lxq+k));
const __m256i vz=_mm256_loadu_si256((const __m256i*)(lzq+k));
a3=_mm256_sub_epi32(a3,_mm256_and_si256(_mm256_cmpgt_epi32(x3,vx),_mm256_cmpgt_epi32(t3,vz))); }
c3=k<G3?tl(x3,t3,k,G3-k):0;
}
const __m256i h01=_mm256_hadd_epi32(a0,a1),h23=_mm256_hadd_epi32(a2,a3);
const __m256i h=_mm256_hadd_epi32(h01,h23);
const __m128i sums=_mm_add_epi32(_mm256_castsi256_si128(h),_mm256_extracti128_si256(h,1));
c0+=(u32)_mm_cvtsi128_si32(sums);c1+=(u32)_mm_extract_epi32(sums,1);
c2+=(u32)_mm_extract_epi32(sums,2);c3+=(u32)_mm_extract_epi32(sums,3);
ltmp[2*q]+=c0; ltmp[2*(q+1)]+=c1; ltmp[2*(q+2)]+=c2; ltmp[2*(q+3)]+=c3;
g=G3;
}
}
const auto reduce=[](__m256i v)->u32{
__m128i sum=_mm_add_epi32(_mm256_castsi256_si128(v),_mm256_extracti128_si256(v,1));
sum=_mm_add_epi32(sum,_mm_shuffle_epi32(sum,0x4e));
sum=_mm_add_epi32(sum,_mm_shuffle_epi32(sum,0xb1));return (u32)_mm_cvtsi128_si32(sum);
};
for(;q+1<sn;q+=2){
if((lk[q]>>8)!=(lk[q-1]>>8))g=q;
const int g0=g,g1=((lk[q+1]>>8)!=(lk[q]>>8))?q+1:g;
const __m256i x0=_mm256_set1_epi32(lxq[q]),t0=_mm256_set1_epi32(ltq[q]);
const __m256i x1=_mm256_set1_epi32(lxq[q+1]),t1=_mm256_set1_epi32(ltq[q+1]);
__m256i a0=_mm256_setzero_si256(),a1=a0;
int k=0;
for(;k+8<=g0;k+=8){
__m256i vx=_mm256_loadu_si256((const __m256i*)(lxq+k));
__m256i vz=_mm256_loadu_si256((const __m256i*)(lzq+k));
a0=_mm256_sub_epi32(a0,_mm256_and_si256(_mm256_cmpgt_epi32(x0,vx),_mm256_cmpgt_epi32(t0,vz)));
a1=_mm256_sub_epi32(a1,_mm256_and_si256(_mm256_cmpgt_epi32(x1,vx),_mm256_cmpgt_epi32(t1,vz)));
}
u32 c0=reduce(a0);
if(k<g0){__m256i c=_mm256_and_si256(_mm256_cmpgt_epi32(x0,_mm256_loadu_si256((const __m256i*)(lxq+k))),_mm256_cmpgt_epi32(t0,_mm256_loadu_si256((const __m256i*)(lzq+k))));c0+=(u32)__builtin_popcount(_bzhi_u32((u32)_mm256_movemask_ps(_mm256_castsi256_ps(c)),g0-k));}
for(;k+8<=g1;k+=8){__m256i c=_mm256_and_si256(_mm256_cmpgt_epi32(x1,_mm256_loadu_si256((const __m256i*)(lxq+k))),_mm256_cmpgt_epi32(t1,_mm256_loadu_si256((const __m256i*)(lzq+k))));a1=_mm256_sub_epi32(a1,c);}
u32 c1=reduce(a1);
if(k<g1){__m256i c=_mm256_and_si256(_mm256_cmpgt_epi32(x1,_mm256_loadu_si256((const __m256i*)(lxq+k))),_mm256_cmpgt_epi32(t1,_mm256_loadu_si256((const __m256i*)(lzq+k))));c1+=(u32)__builtin_popcount(_bzhi_u32((u32)_mm256_movemask_ps(_mm256_castsi256_ps(c)),g1-k));}
ltmp[2*q]+=c0;ltmp[2*(q+1)]+=c1;g=g1;
}
for (; q < sn; q++) {
if((lk[q]>>8)!=(lk[q-1]>>8))g=q;
const u32 xj = lxq[q], tj = ltq[q];
const __m256i mxj = _mm256_set1_epi32((int)xj);
const __m256i mtj = _mm256_set1_epi32((int)tj);
u32 acc = 0;
__m256i vacc=_mm256_setzero_si256();
int k = 0;
for (; k + 8 <= g; k += 8) {
__m256i c = _mm256_and_si256(_mm256_cmpgt_epi32(mxj, _mm256_loadu_si256((const __m256i *)(lxq + k))),
_mm256_cmpgt_epi32(mtj, _mm256_loadu_si256((const __m256i *)(lzq + k))));
vacc=_mm256_sub_epi32(vacc,c);
}
__m128i sum=_mm_add_epi32(_mm256_castsi256_si128(vacc),_mm256_extracti128_si256(vacc,1));
sum=_mm_add_epi32(sum,_mm_shuffle_epi32(sum,0x4e));sum=_mm_add_epi32(sum,_mm_shuffle_epi32(sum,0xb1));acc=(u32)_mm_cvtsi128_si32(sum);
if(k<g){__m256i c=_mm256_and_si256(_mm256_cmpgt_epi32(mxj,_mm256_loadu_si256((const __m256i*)(lxq+k))),_mm256_cmpgt_epi32(mtj,_mm256_loadu_si256((const __m256i*)(lzq+k))));acc+=(u32)__builtin_popcount(_bzhi_u32((u32)_mm256_movemask_ps(_mm256_castsi256_ps(c)),g-k));}
ltmp[2 * q] += acc;
}
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;
}
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 >> 20) & 0xFFFFFu);
ley[k] = (u32)(w0 >> 40);
ler[k] = (u32)(w1 & 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;
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)))));
acc += (u32)__builtin_popcount((u32)_mm256_movemask_ps(_mm256_castsi256_ps(c)));
}
for (; k < jl; k++) acc += (u32)((lex[k] < xj) & (ley[k] < yj) & (ler[k] < tj));
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] << 7) | (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 if (sn <= 128) {
// sn in (64,128]: fixed sort each 64-key half, then bitonic-merge (branch-free)
for (int k = 0; k < sn; k++) lk[k] = (ley[k] << 7) | (u32)k;
for (int k = sn; k < 128; 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 q = 0; q < 8; q++) r[q] = _mm256_load_si256((const __m256i *)(lk + 64 + 8 * q));
bs64(r);
for (int q = 0; q < 8; q++) _mm256_store_si256((__m256i *)(lk + 64 + 8 * q), r[q]);
}
bm128(lk);
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 {
for (int k = 0; k < sn; k++) lkey[k] = ((u64)ley[k] << 20) | (u64)(u32)k;
for (int i = 1; i < sn; i++) {
u64 kv = lkey[i];
int k = i;
while (k > 0 && lkey[k - 1] > kv) { lkey[k] = lkey[k - 1]; k--; }
lkey[k] = kv;
}
for (int k = 0; k < sn; k++) {
const int sr = (int)(u32)(lkey[k] & 0xFFFFFu);
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)
template <int LV, int LF> static int cdq(int l, int r, int in) {
int s = r - l;
if (s <= 1) return in;
if (s <= LF) return (LF == 256) ? cdq_leaf256(l, r, in) : cdq_leaf(l, r, in);
int m = (l + r) >> 1;
int isroot = (g_root_pending && l == 0 && r == g_nz);
if (isroot) g_root_pending = 0;
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; }
}
}
int b1 = cdq<LV, LF>(l, m, in);
int b2 = cdq<LV, LF>(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 (isroot) { node_fused_root<LV>(l, m, r, b1); return -1; }
node_fused<LV>(l, m, r, b1, out);
return out;
}
if (mode == 2) {
int out = 1 - b1;
merge_run(l, m, r, b1, out);
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);
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; }
g_nz = n;
mktab();
// [r2e_] Compact exact17-bit rank starts for the100000-point production shape.
// The four temp arrays live INSIDE RC[1]'s record window [0, 2n*u64) -- that window is
// dirtied by the CDQ ping-pong anyway, and these temps are dead before the first merge
// (judge bills touched pages only, so this removes ~1.0 MB = 250 pages from the bill).
unsigned char *histx=(unsigned char *)(void *)RC[1], *histz=histx+131072;
u32 *hz=(u32 *)(void *)(histx+262144);
u32 *hc=(u32 *)(void *)(histx+786432); // x-cursor (replaces the alias CNT here)
bool narrow=n<131072;
if(narrow){
memset(histx,0,(size_t)n+1);memset(histz,0,(size_t)n+1);
for(int i=0;i<n;i++){histx[x[i]]++;histz[z[i]]++;}
u32 sx=0,sz=0;
{
int v=0;
for(;v+16<=n+1;v+=16){
auto build16 = [&](const unsigned char* h,u32* p,u32& sum) {
__m256i raw=_mm256_cvtepu8_epi16(_mm_loadu_si128((const __m128i*)h));
__m256i val=_mm256_add_epi16(raw,_mm256_slli_si256(raw,2));
val=_mm256_add_epi16(val,_mm256_slli_si256(val,4));
val=_mm256_add_epi16(val,_mm256_slli_si256(val,8));
__m256i low=_mm256_permute2x128_si256(val,val,0x08);
low=_mm256_shuffle_epi8(low,_mm256_set1_epi16(0x0f0e));
val=_mm256_add_epi16(val,low);
__m256i ex=_mm256_sub_epi16(val,raw);
__m256i base=_mm256_set1_epi32((int)sum);
_mm256_storeu_si256((__m256i*)p,_mm256_add_epi32(base,_mm256_cvtepu16_epi32(_mm256_castsi256_si128(ex))));
_mm256_storeu_si256((__m256i*)(p+8),_mm256_add_epi32(base,_mm256_cvtepu16_epi32(_mm256_extracti128_si256(ex,1))));
sum+=(unsigned)_mm256_extract_epi16(val,15);
};
build16(histx+v,hc+v,sx);build16(histz+v,hz+v,sz);
}
for(;v<=n;v++){u32 cx=histx[v],cz=histz[v];hc[v]=sx;hz[v]=sz;sx+=cx;sz+=cz;}
}
narrow=(sx==(u32)n&&sz==(u32)n);
}
if(narrow){
u64 *D=RC[0];
for(int i=0;i<n;i++){
if(i+32<n){__builtin_prefetch(&D[2*hc[x[i+32]]]);__builtin_prefetch(&hz[z[i+32]]);__builtin_prefetch(&hc[x[i+48]]);}
u32 zv=z[i],h=hz[zv],T=h&0x1ffffu,R=T+(h>>17);
hz[zv]=h+(1u<<17);
u32 xv=x[i],t=hc[xv]++;
__m128i rv=_mm_set_epi64x((long long)(((u64)T<<40)|((u64)xv<<20)|R),(long long)(((u64)y[i]<<40)|((u64)i<<20)));
_mm_storeu_si128((__m128i*)(void*)(D+2*t),rv);
}
}else{
// ---- FUSED BUILD: histograms, then ONE scatter pass (no P0/P1 arrays) ----
memset(H64, 0, (size_t)(n + 1) * 8);
memset(CNT, 0, (size_t)(n + 1) * 4);
for (int i = 0; i < n; i++) {
H64[z[i]]++;
CNT[x[i]]++;
}
{
u32 acc = 0;
for (int v = 0; v <= n; v++) { u32 c = (u32)(H64[v] & 0xFFFFFu); H64[v] = (u64)acc << 20; acc += c; }
}
{
u32 acc = 0;
int v = 0;
for (; v + 8 <= n + 1; v += 8) {
__m256i x = _mm256_loadu_si256((const __m256i *)(CNT + v));
__m256i p = _mm256_add_epi32(x, _mm256_slli_si256(x, 4));
p = _mm256_add_epi32(p, _mm256_slli_si256(p, 8));
__m128i lo = _mm256_castsi256_si128(p);
__m128i hi = _mm256_extracti128_si256(p, 1);
hi = _mm_add_epi32(hi, _mm_shuffle_epi32(lo, 0xFF));
__m256i pi = _mm256_inserti128_si256(_mm256_castsi128_si256(lo), hi, 1);
__m256i ex = _mm256_add_epi32(_mm256_sub_epi32(pi, x), _mm256_set1_epi32((int)acc));
_mm256_storeu_si256((__m256i *)(CNT + v), ex);
acc += (u32)_mm_extract_epi32(hi, 3);
}
for (; v <= n; v++) { u32 c = CNT[v]; CNT[v] = acc; acc += c; }
}
{
u64 *D = RC[0];
for (int i = 0; i < n; i++) {
if (i + 12 < n) { __builtin_prefetch(&D[2 * CNT[x[i + 12]]]); }
u32 zv = z[i];
u64 h = H64[zv];
u32 T = (u32)(h >> 20);
u32 R = T + (u32)(h & 0xFFFFFu);
H64[zv] = h + 1;
u32 xv = x[i];
u32 t = CNT[xv]++;
__m128i _rv = _mm_set_epi64x((long long)(((u64)T << 40) | ((u64)xv << 20) | (u64)R),
(long long)(((u64)y[i] << 40) | ((u64)i << 20)));
_mm_storeu_si128((__m128i *)(void *)(D + 2 * t), _rv);
}
}
}
// ---- tie bits over x-order positions ----
// ---- CDQ ----
// (ENGINE, SIZE)-dependent: measured optima are LF=16 at n=1e5 and LF=24 at n=1e6.
g_rootout = out; g_root_pending = 1;
int bb = (n <= 262144) ? cdq<3, 256>(0, n, 0) : cdq<4, 64>(0, n, 0);
g_root_pending = 0; g_rootout = 0;
if (bb >= 0) {
const u64 *D = RC[bb];
for (int p = 0; p < n; p++) {
if (p + 64 < n) __builtin_prefetch(&out[W_ORIG(D[2 * (p + 64)])]);
out[W_ORIG(D[2 * p])] = W_A(D[2 * p]);
}
}
}
| Compilation | N/A | N/A | Compile OK | Score: N/A | 显示更多 |
| Testcase #1 | 7.531 ms | 3 MB + 500 KB | Accepted | Score: 100 | 显示更多 |