莫队

莫队是一种对于询问做转移的算法。

对于可以离线, 运算可逆的题目。

如果按题目给的顺序操作, 可以被以下数据 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\)

在顺便维护一下众数就行了。

代码, 题目 luoguP1997

如果强制在线

这里

posted @ 2024-04-18 16:39  liuyichen  阅读(3)  评论(0编辑  收藏  举报