题意:

给出个数,求 ,这两个区间不同数的个数

思路:

其实只要把区间扩大一倍,就是求这个区间了

定义数组中第一次出现的数的后缀为,第次出现的数的后缀为该数第次出先时的下标。比如:原数组为,扩大一倍后为,每个数对应的后缀为

如果某个数出现多次,而我们只算最右边的那个,我们会发现最右边的那个数的后缀一定是大于区间右端点的,其它的数的后缀一定是小于等于区间右端点的,所以我们只要把后缀大于区间右端点的数的下标取出来,然后用树状数组计算区间内有多少个数。

code;

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+7;
int head[maxn],c[maxn],Next[maxn],ans[maxn];
struct node {
    int l,r,x,id;
    bool operator<(const node& b)const {
        if(x!=b.x) return x>b.x;
        else if(id!=b.id) return id>b.id;
        else return l<b.l;
    }
};
vector<node>v;
int sum[maxn],m;
inline void add(int p,int v) {
    while(p<=m) {
        sum[p]+=v;
        p+=(p&-p);
    }
}
inline int query(int p) {
    int res(0);
    while(p) {
        res+=sum[p];
        p-=(p&-p);
    }
    return res;
}
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    int n,Q;
    while(cin>>n>>Q) {
        for(int i=1; i<=n; ++i) cin>>c[i],c[i+n]=c[i];
        m=n*2;
        for(int i=m; i; --i) {
            if(!head[c[i]]) Next[i]=m+1;
            else Next[i]=head[c[i]];
            head[c[i]]=i;
            v.emplace_back(node {i,0,Next[i],0});
        }
        for(int i=1,l,r; i<=Q; ++i) {
            cin>>l>>r;
            v.emplace_back(node {r,n+l,n+l,i});
        }
        sort(v.begin(),v.end());
        for(node i:v) {
            if(!i.id) add(i.l,1);
            else ans[i.id]+=query(i.r)-query(i.l-1);
        }
        for(int i=1; i<=Q; ++i) {
            cout<<ans[i]<<'\n';
            ans[i]=0;
        }
        for(node i:v) if(!i.id) add(i.l,-1);
        for(int i=1; i<=n; ++i) head[c[i]]=0;
        v.clear();
    }
    return 0;
}