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;
}
原文地址:https://www.cnblogs.com/sdfzsyq/p/9676883.html