Link to this code: https://cses.fi/paste/ec649550a7cf002116171a/
#include <bits/stdc++.h>

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

typedef long long ll;
typedef vector<int> vi;
typedef pair<int, int> pii;
template <class T>
using Tree = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#ifdef LOCAL
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
#else
#define trace(...) 42
#endif
template <typename Arg1>
void __f(const char *name, Arg1 &&arg1) {
    cerr << name << ": " << arg1 << endl;
}
template <typename Arg1, typename... Args>
void __f(const char *names, Arg1 &&arg1, Args &&... args) {
    const char *comma = strchr(names + 1, ',');
    cerr.write(names, comma - names) << ": " << arg1 << "\t|";
    __f(comma + 1, args...);
}

#define print(x)           \
    for (auto it : x)      \
        cout << it << ' '; \
    cout << '\n';
#define mem1(a) memset(a, -1, sizeof(a))
#define mem0(a) memset(a, 0, sizeof(a))
#define int long long

// typedef long long ll;
typedef unsigned long long ull;

const int N = 2e5 + 5;
const int BLOCK = 447;  // ~sqrt(N)

int a[N], ans[N], answer = 0;
int cnt[N];
// unordered_map<int, int> cnt;
struct node {
    int L, R, i;
};
node q[N];

bool cmp(node x, node y) {
    if (x.L / BLOCK != y.L / BLOCK) {
        // different blocks, so sort by block.
        return x.L / BLOCK < y.L / BLOCK;
    }
    // same block, so sort by R value
    return x.R < y.R;
}

void add(int position) {
    cnt[a[position]]++;
    if (cnt[a[position]] == 1) {
        answer++;
    }
}

void remove(int position) {
    cnt[a[position]]--;
    if (cnt[a[position]] == 0) {
        answer--;
    }
}

void solve() {
    int n, m;
    cin >> n >> m;

    vector<int> v(n);
    for (int i = 0; i < n; i++) {
        cin >> v[i];
        a[i] = v[i];
    }
    sort(v.begin(), v.end());
    v.erase(unique(v.begin(), v.end()), v.end());
    // print(v);

    map<int, int> new_num;
    for (int i = 0; i < n; i++) new_num[v[i]] = i;
    // for (auto el : new_num) {
    //     cout << "lol "<< el.first << ' ' << el.second << '\n';
    // }

    for (int i = 0; i < n; i++) a[i] = new_num[a[i]];
    // print(a);

    // before this point you want your a array to contain compressed values
    // in the original order
    for (int i = 0; i < m; i++) {
        int x, y;
        cin >> x >> y;
        q[i].L = --x;
        q[i].R = --y;
        q[i].i = i;
    }
    sort(q, q + m, cmp);

    int currentL = 0, currentR = 0;
    for (int i = 0; i < m; i++) {
        int L = q[i].L, R = q[i].R;
        while (currentL < L) {
            remove(currentL);
            currentL++;
        }
        while (currentL > L) {
            add(currentL - 1);
            currentL--;
        }
        while (currentR <= R) {
            add(currentR);
            currentR++;
        }
        while (currentR > R + 1) {
            remove(currentR - 1);
            currentR--;
        }
        ans[q[i].i] = answer;
    }

    for (int i = 0; i < m; i++)
        cout << ans[i] << '\n';
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t = 1;
    // cin >> t;
    while (t--) solve();
    return 0;
}