1. 程式人生 > >【題解】Luogu P3901 數列找不同

【題解】Luogu P3901 數列找不同

原題傳送門

不錯的莫隊練手題

塊數就直接取sqrt(n)

對所有詢問進行排序

排序第一關鍵詞:l所在第幾塊,第二關鍵詞:r的位置

考慮Ai不大,暴力開陣列

add時如果加之後的數量是1

總數就加1

del時如果減之後的數量是0

總數就減1

每次比較總數和該次查詢區間的長度

相等的話就把 ans[q[i].id]設為真

最後如果ans[i]為真就輸出Yes,否則輸出No

#pragma GCC optimize("O3")
#include <bits/stdc++.h>
#define N 100005
using namespace std;
inline int read()
{
    register int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
int v[N],blocksize=0;
struct query{
    int l,r,id,bl;
}q[N];
int sum[N];
bool ans[N];
int cnt=0;
inline void add(register int x)
{
    if(++sum[v[x]]==1)
        ++cnt; 
}
inline void del(register int x)
{
    if(--sum[v[x]]==0)
        --cnt;
}
inline bool cmp(register query a,register query b)
{
    return a.bl==b.bl?a.r<b.r:a.bl<b.bl;
}
int main()
{
    memset(sum,0,sizeof(sum));
    int n=read(),m=read();
    blocksize=sqrt(n);
    for(register int i=1;i<=n;++i)
        v[i]=read();
    for(register int i=1;i<=m;++i)
    {
        int l=read(),r=read();
        q[i]=(query){l,r,i,(l-1)/blocksize+1};
    }
    sort(q+1,q+m+1,cmp);
    int l=1,r=0;
    for(register int i=1;i<=m;++i)
    {
        int ll=q[i].l,rr=q[i].r;
        while(l<ll)
            del(l++);
        while(l>ll)
            add(--l);
        while(r<rr)
            add(++r);
        while(r>rr)
            del(r--);
        ans[q[i].id]=(cnt==rr-ll+1)?1:0;
    }
    for(register int i=1;i<=m;++i)
        if(ans[i])
            puts("Yes");
        else
            puts("No");
    return 0;
 }