说在前面:
- 莫队算法只能用于离线查询:什么是离线查询,就是输入了查询的区间,不用立即给出答案,可以在所有的区间都输入完毕之后统一的给出答案
- 要是我们用最笨的方法:就是直接计算相应的区间和,那离线的优势你就没有用到
- 另一种方法:
- 但是这种方法有个漏洞:
要是左右横条太剧烈,那就很难受,因为每次都是一步一步跳那么多次,失去了优势
- 能不能有一种查询顺序让左右横条少点了
莫队
- 我们把要查询的 L R 区间存起来,排个序
要是按照L 排序,那么极端情况就是R 从最右到最左再到最右,一直这样 - 我们按照R 排序,同理
- 莫队结合了块的思:
L 所在块为第一关键字
R 的位置就第二关键字
假设 按序号(id)1 2 3 的顺序查询
我们排个序变成了 2 1 3
但是我们输出的时候不能按照 2 1 3 的循序输出,所以要记录我们的最开始 的 循序 也就是id 为 1 2 3
要是再加上序号4:
循序就是2 1 3 4 的循序,但是还是要记录id
这就是莫队算法的过程。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int sizen;
struct node{
int l,r,id;
bool operator < (const node & n) const {
if(l/sizen==n.l/sizen)return r<n.r;
else return l/sizen< n.l/sizen;
}
}q[maxn];
int n,m;
int data[maxn];
int Ans[maxn];
int ans;
void add(int n){
}
void sub(int n){
}
main(){
cin>>n>>m;
for(int a=0;a<n;a++){
cin>>data[a];
}
for(int a=0;a<m;a++){
cin>>q[a].l>>q[a].r;
q[a].id=a;
}
sort(q,q+m);
/// 首先要定义当前的 L R
/// 初始化的时候要是空集 也就是什么也不包含
/// L 比 R 还 右 就是什么也不包含,但是只要一个动了,就包含了一个;
int l=1;
int r=0;
for(int a=0;a<m;a++){
while(l<q[a].l)sub(l--);
while(l>q[a].l)add(--l);
while(r<q[a].r)add(++r);
while(r>q[a].r)sub(r++);
Ans[q[a].id]=ans;
}
}
看代码就知道 核心的算法就是
for(int a=0;a<m;a++){
while(l<q[a].l)sub(l--);
while(l>q[a].l)add(--l);
while(r<q[a].r)add(++r);
while(r>q[a].r)sub(r++);
Ans[q[a].id]=ans;
}
要注意不同的题目的add 和sub函数不同,要自己写就完事了!