LUOGU P3901 数列找不同
解题思路
莫队第一题,离线神器。先分块,然后按左端点的块为第一关键字,右端点为第二关键字排序,然后类似暴力的统计答案。时间复杂度O(nsqrt(n)) (不会证。。。)
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int MAXN = 1e5+5;
inline int rd(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {f=ch=='-'?-1:1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
int n,m,siz,num,L,R,now;
int a[MAXN],bl[MAXN];
int b[MAXN],ans[MAXN];
struct Ask{
int l,r,id;
}q[MAXN];
inline bool cmp(Ask A,Ask B){
if(bl[A.l]==bl[B.l]) return A.r<B.r;
return bl[A.l]<bl[B.l];
}
inline bool cmp2(Ask A,Ask B){
return A.id<B.id;
}
int main(){
n=rd();m=rd();
siz=sqrt(n)+1;num=n/siz;if(n%siz) num++;
for(register int i=1;i<=n;i++) {
a[i]=rd();
bl[i]=(i-1)/siz+1;
}
for(register int i=1;i<=m;i++) q[i].l=rd(),q[i].r=rd(),q[i].id=i;
sort(q+1,q+1+m,cmp);
L=0,R=0;now=0;
for(register int i=1;i<=m;i++) {
while(R<q[i].r) {R++;if(!b[a[R]]) now++;b[a[R]]++;}
while(R>q[i].r){b[a[R]]--;if(!b[a[R]]) now--;R--;}
while(L<q[i].l){b[a[L]]--;if(!b[a[L]]) now--;L++;}
while(L>q[i].l){L--;if(!b[a[L]]) now++;b[a[L]]++;}
if(now==q[i].r-q[i].l+1) ans[q[i].id]=1;
}
sort(q+1,q+1+m,cmp2);
for(register int i=1;i<=m;i++)
puts(ans[i]==1?"Yes":"No");
return 0;
}