牛客网暑期ACM多校训练营(第一场)- J Different Integers (莫队)

题意:裸的莫队题,每个查询Li,Ri,返回区间[1,Li]和[Ri,N]区间中不同的数的个数。

分析:正常的离线查询,是求区间[Li,Ri]中要求的答案,而该题所求答案为外侧两个区间中的答案,那么cnt[i]维护的东西修改一下即可。对查询排序的时候,将R较大的排在前面,因为对于所维护的区间,是从两侧往内递推过来的,这样才能令不必要的递推减少。

此外,也有用主席树和树状数组的做法。

#include<bits/stdc++.h>
using namespace std;
const int maxn =1e5+5;
int pos[maxn];
struct Query{
    int L,R,id;
    bool operator <(const Query q) const{
        if(pos[L]==pos[q.L]) return R>q.R;
        return pos[L]<pos[q.L]; 
    }
}Q[maxn];
int a[maxn];
int ans[maxn];
int block;
int cnt[maxn];
int vis[maxn];
int res;
 
//区间是相反的
void add(int pos)
{
    cnt[a[pos]]++;
    if(cnt[a[pos]]==1) res++;
}
 
void pop(int pos){
    cnt[a[pos]]--;
    if(cnt[a[pos]]==0) res--;
}
 
int main()
{
    int n,q;
    while(scanf("%d%d",&n,&q)==2){
        memset(cnt,0,sizeof(cnt));       
        block  =ceil(sqrt(1.0*n));
        for(int i=1;i<=n;++i){
            scanf("%d",&a[i]);   
            pos[i] = i/block;
        }
        for(int i=1;i<=q;++i){
            scanf("%d%d",&Q[i].L,&Q[i].R);
            Q[i].id = i;
        }
        sort(Q+1,Q+q+1);
        int curL=0,curR=n+1;
        res=0;
        for(int i=1;i<=q;++i){
            //外区间缩
            while(curL>Q[i].L) pop(curL--);
            while(curR<Q[i].R) pop(curR++);
            //外区间扩
            while(curL<Q[i].L) add(++curL);
            while(curR>Q[i].R) add(--curR);
             
            ans[Q[i].id] = res;       
        }
        for(int i=1;i<=q;++i){
            printf("%d\n",ans[i]);
        }
    }
}

 

posted @ 2018-07-19 18:27  xiuwenL  阅读(227)  评论(0编辑  收藏  举报