P3901 数列找不同(莫队)

传送门:数列找不同
显然一个区间的答案可以 \(O(1)\) 转移到相邻区间,记录每个数的 \(cnt\)。当 \(cnt = 2\) 时,表示多出现了一个相同的,记录增加。同理,当 \(cnt = 1\) 的时候,表示少了一个相同的,记录减少。跑一遍莫队即可,时间复杂度 \(O(n\sqrt n)\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100000 + 10;
struct unit
{
    int l,r,id;
} q[N];
int n,m,l = 1,r,block,res;
int a[N],cnt[N],L[N],R[N],spl[N];
map < int ,string > ans;
bool cmp(unit aa,unit bb)
{
    if(spl[aa.l] != spl[bb.l]) return spl[aa.l] < spl[bb.l];
    if(spl[aa.l] & 1) return aa.r < bb.r;
    else return aa.r > bb.r;
}
void modify(int x,int val)
{
    cnt[a[x]] += val;
    if(val == 1) res += (cnt[a[x]] == 2);
    else res -= (cnt[a[x]] == 1);
}
signed main()
{
    scanf("%lld%lld",&n,&m);
    for(int i = 1;i <= n;i++) scanf("%lld",&a[i]);
    block = sqrt(n);
    for(int i = 1;i <= block;i++)
    {
        L[i] = (i - 1) * block + 1;
        R[i] = i * block;
    }
    if(R[block] < n) block++,L[block] = R[block - 1] + 1,R[block] = n;
    for(int i = 1;i <= block;i++)
        for(int j = L[i];j <= R[i];j++)
            spl[j] = i;
    for(int i = 1;i <= m;i++)
    {
        scanf("%lld%lld",&q[i].l,&q[i].r);
        q[i].id = i;
    }
    sort(q + 1,q + m + 1,cmp);
    for(int i = 1;i <= m;i++)
    {
        while(l > q[i].l) modify(--l,1);
        while(r < q[i].r) modify(++r,1);
        while(l < q[i].l) modify(l++,-1);
        while(r > q[i].r) modify(r--,-1);
        ans[q[i].id] = res ? "No" : "Yes";
    }
    for(int i = 1;i <= m;i++) cout << ans[i] << endl;
    return 0;
}
posted @ 2021-12-13 16:59  一程山雪  阅读(55)  评论(0)    收藏  举报