社区讨论

对空间为 N sqrt N 的分块的卡常建议

P6774[NOI2020] 时代的眼泪参与者 1已保存回复 0

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
0 条
当前快照
1 份
快照标识符
@mjthnosh
此快照首次捕获于
2025/12/31 12:00
2 个月前
此快照最后确认于
2026/01/02 21:35
2 个月前
查看原帖
当然我不是专业的,下面的内容不保证一定有道理,仅供参考。
首先可以尝试调整数组的维度,把循环中不变的放在前面。
接下来,如果前面的维度不变了(循环中每次都不变,或者多次访问中不变),可以用指针存下来,以后访问指针。我就用这个方法在 UOJ 上卡过了。
举几个例子(uiunsigned int。不必理解变量名,理解原理就行了):
  • 散块内部(循环中每次都不变):
CPP
ui bid = pos[l];
Block& b = block[bid];
ui b_l = bl[bid], rk_d_1 = b.rk[d - 1];
ui* b_les_l_b_l = b.les[l - b_l];
FOR(i, l, r) {
    if (d <= a[i] && a[i] <= u) {
        ans += b.les[i - b_l][b.rk[a[i]]] - b.les[i - b_l][rk_d_1] -
               b.les[l - b_l][b.rk[a[i]]] + b.les[l - b_l][rk_d_1];
    }
}
式子的后面两项中,每次都是 b.les[l - b_l][...][...],因此可以改成:
CPP
            ui* ptr = b.les[l - b_l];
            FOR(i, l, r) {
                if (d <= a[i] && a[i] <= u) {
                    ans += b.les[i - b_l][b.rk[a[i]]] - b.les[i - b_l][rk_d_1] -
                           ptr[b.rk[a[i]]] + ptr[rk_d_1];
                }
            }
  • 整块之间(多次访问中不变)
其中有一部分式子长这样:
CPP
ctb[j][j - 1][b.rk[u]] - ctb[j][j - 1][b.rk[d - 1]] -
ctb[j][l - 1][b.rk[u]] + ctb[j][l - 1][b.rk[d - 1]] - /* 另一坨式子 */
这里虽然 j 是循环变量,但是每次都有 ctb[j],因此可以把 ctb[j] 存起来:
CPP
ui (*ptr)[MAXBLEN] = ctb[j]; // MAXBLEN 是数组第 3 维的大小

ptr[j - 1][b.rk[u]] - ptr[j - 1][b.rk[d - 1]] -
ptr[l - 1][b.rk[u]] + ptr[l - 1][b.rk[d - 1]] - /* 另一坨式子 */

回复

0 条回复,欢迎继续交流。

正在加载回复...