莫队算法
mind:
分块
离散化
通过合理地对询问排序,然后以较优的顺序暴力回答每个询问(两个指针左右扩张或缩小范围)
借题理解
莫队发展里程
1.首先这个题很明显可以暴力跑,然后开个桶记录一下(慢到家)
2.珂以在区间\([1,5]\)的基础上,去掉位置 \(1\)(即将左端点右移一位),加上位置 \(6\)(即将右端点右移一位),得到区间\([2,6]\)的答案
对于\([99999,100000]\)这样的鬼畜数据肯定会被卡
所以就莫队就从此把分块纳了进去,先对数据进行了排序,然后在由上述操作锁定区间
怎样排序捏??
莫队提供了这样一个排序方案:将原序列以\(n^{1/2}\)为一块进行分块(分块的大小也珂以调整),排序第一关键字是询问的左端点所在块的编号,第二关键字是询问的右端点本身的位置,都是升序。然后我们用上面提到的“移动当前区间左右端点”的方法,按顺序求每个询问区间的答案,移动每一个询问区间左右端点可以求出下一个区间的答案
排序:
bool cmp(Query a,Query b)
{
return a.bl==b.bl?a.r<b.r:a.bl<b.bl;
}
但由于出题人过于狠毒
又多出一种优化,叫做奇偶优化
按奇偶块排序。这也是比较通用的。如果区间左端点所在块不同,那么就直接按左端点从小到大排;如果相同,奇块按右端点从小到大排,偶块按右端点从大到小排
node
bool cmp(Query a,Query b)
{
return a.bl!=b.bl?a.l<b.l:((a.bl&1)?a.r<b.r:a.r>b.r);
}
核心代码
sort(q + 1,q + m + 1, cmp);
for(int i = 1;i <= m; i++){
L = q[i].l,R = q[i].r;
while(nl < L) del(nl++);
while(nl > L) add(--nl);
while(nr < R) add(++nr);
while(nr > R) del(nr--);
if(ans == (R - L + 1)){
ANS[q[i].num] = 1;
}
}
复杂度
\(O(n*n^{1/2})\)
/*
work by:Ariel_
*/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define N 100010
using namespace std;
typedef long long ll;
int read(){
int x = 0,f = 1;char c = getchar();
while(c < '0'||c > '9'){
if(c == '-')f = -1;c = getchar();}
while(c >= '0'&& c <= '9'){x = x*10 + c - '0',c = getchar();}
return x*f;
}
int n,m,lucky_block,L,R,a[N],nl,nr,ANS[N],ans,cnt[N];
struct Query{
int l, r , num;
}q[N];
bool cmp(Query a,Query b){
return (a.l/lucky_block) == (b.l/lucky_block) ? a.r < b.r : a.l < b.l;//排序
}
void add(int pos){
if(++cnt[a[pos]] == 1) ans++;
}
void del(int pos){
if(--cnt[a[pos]] == 0) ans--;
}
int main(){
n = read(),m = read();
lucky_block = sqrt(n);
for(int i = 1;i <= n; i++){
a[i] = read();
}
for(int i = 1; i <= m; i++){
q[i].l = read();
q[i].r = read();
q[i].num = i;
}
sort(q + 1,q + m + 1, cmp);
for(int i = 1;i <= m; i++){
L = q[i].l,R = q[i].r;
while(nl < L) del(nl++);
while(nl > L) add(--nl);
while(nr < R) add(++nr);
while(nr > R) del(nr--);
if(ans == (R - L + 1)){
ANS[q[i].num] = 1;
}
}
for(int i = 1;i <= m; i++){
if(ANS[i] == 1){
printf("Yes\n");
}
else{
printf("No\n");
}
}
}