OSDN Git Service

Update mo-algo.md
authorakakw1 <44433637+akakw1@users.noreply.github.com>
Sat, 8 Dec 2018 03:11:48 +0000 (11:11 +0800)
committerGitHub <noreply@github.com>
Sat, 8 Dec 2018 03:11:48 +0000 (11:11 +0800)
docs/misc/mo-algo.md

index 3dbfdd3..a0cb3fb 100644 (file)
@@ -161,6 +161,53 @@ int main() {
 }
 ```
 
+## 普通莫队的优化
+
+我们看一下下面这组数据
+
+```
+// 设块的大小为 2 (假设)
+1 1
+2 100
+3 1
+4 100
+```
+
+手动模拟一下可以发现,r 指针的移动次数大概为 300 次,我们处理完第一个块之后,$l = 2, r = 100$,此时只需要移动两次 l 指针就可以得到第四个询问的答案,但是我们却将 r 指针移动到 1 来获取第三个询问的答案,再移动到 100 获取第四个询问的答案,这样多了九十几次的指针移动。我们怎么优化这个地方呢?这里我们就要用到奇偶化排序
+
+什么是奇偶化排序?奇偶化排序即对于属于奇数块的询问,r 按从小到大排序,对于属于偶数块的排序,r 从大到小排序,这样我们的 r 指针在处理完这个奇数块的问题后,将在返回的途中处理偶数块的问题,再向 n 移动处理下一个奇数块的问题,优化了 r 指针的移动次数,一般情况下,这种优化能让程序快 30% 左右
+
+排序代码:
+
+压行
+```cpp
+// 这里有个小细节等下会讲
+int unit; // 块的大小
+struct node {
+       int l, r, id;
+       bool operator < (const node &x)const {
+               return l / unit == x.l /unit ? (r == x.r ? 0 : ((l / unit) & 1) ^ (r < x.r)) : l < x.l;
+       }
+};
+```
+
+不压行
+```cpp
+struct node {
+       int l, r, id;
+       bool operator < (const node &x)const {
+               if(l / unit != x.l / unit)return l < x.l;
+               if((l / unit) & 1)return r < x.r; // 注意这里和下面一行不能写小于(大于)等于,否则会出错(详见下面的小细节)
+               return r > x.r;
+       }
+};
+```
+
+!!! warning
+    小细节:如果使用 sort 比较两个函数,不能出现 $a < b == true$ 且 $b < a == true$ 的情况,否则会运行错误
+
+对于压行版,如果没有 $r == x.r$ 的特判,当 l 属于同一奇数块且 r 相等时,会出现上面小细节中的问题(自己手动模拟一下),对于压行版,如果写成小于(大于)等于,则也会出现同样的问题
+
 ## 带修改
 
 请确保您已经会普通莫队算法了。