莫队
莫队是一种对于询问做转移的算法。
对于可以离线, 运算可逆的题目。
如果按题目给的顺序操作, 可以被以下数据 hack
1 1
n n
1 1
n n
1 1
n n
1 1
n n
...
时间复杂度 \(O(n^2)\)。
我们可以通过某一些排序来降低时间复杂度。
首先, 把这个序列分成 \(\sqrt{n}\) 块, 每一块按右端点递增排序。
证明时间复杂度。
对于每一块, 右端点移动总共次数最多为 \(n\), 左端点一次最多移动 \(\sqrt{n}\), 所有快左端点移动一起最多一起 \(q \sqrt {n}\)。对于任意两个快, 最多右端点移动 \(n\), 最短点移动 \(\sqrt{n}\), 有 \(\sqrt{n}\) 个这种, 所以总时间复杂度为 \(O((n + q)\sqrt{n})\)。
伪代码
for(; l > q[i].l; add(--l)){ // 前面已经算过了 l 的贡献
}
for(; r < q[i].r; add(++r)){ // 前面已经算过了 r 的贡献
}
for(; l < q[i].l; del(l++)){ // 前面已经算过了 l 的贡献, 当前查询不在区间
}
for(; r > q[i].l; del(r--)){ // 前面已经算过了 r 的贡献, 不在当前查询区间
}
众数就是一段区间内出现次数最多的出现次数。
绝对众数就是众数 \(> \frac{n}{2}\)。
绝对众数有一种随机化的算法。
可以随机一个位置, 每一个位置有至少 \(\frac{1}{2}\) 的概率成为众数。
可以直接随机化。
mt19937 gen(time(0));
int Rand(int l, int r){
uniform_int_distribution<int>dist(l, r);
return dist(gen);
}
int S(int l, int r){
for(int i = 30; ~i; i--){
u = Rand(l, r);
// ok 表示统计的答案。
if(/* 合法 */){
return ok;
}
}
return /* 非法表示 */;
}
对于普通的众数。
如果非强制在线
考虑莫队。
定义两个数组 \(cnt_{j}\) 表示在区间中数值为 \(j\) 的出现次数, \(tot_j\) 表示区间内出现次数为 \(j\) 的数量为 \(tot_j\)。
在顺便维护一下众数就行了。