### BUGGY CODE ###

# From: https://github.com/cheran-senthil/PyRival/blob/master/pyrival/data_structures/SegmentTree.py
class SegmentTree:
    def __init__(self, data, default=0, func=max):
        """initialize the segment tree with data"""
        self._default = default
        self._func = func
        self._len = len(data)
        self._size = _size = 1 << (self._len - 1).bit_length()

        self.data = [default] * (2 * _size)
        self.data[_size : _size + self._len] = data
        for i in reversed(range(_size)):
            self.data[i] = func(self.data[i + i], self.data[i + i + 1])

    def __delitem__(self, idx):
        self[idx] = self._default

    def __getitem__(self, idx):
        return self.data[idx + self._size]

    def __setitem__(self, idx, value):
        idx += self._size
        self.data[idx] = value
        idx >>= 1
        while idx:
            self.data[idx] = self._func(self.data[2 * idx], self.data[2 * idx + 1])
            idx >>= 1

    def __len__(self):
        return self._len

    def query(self, start, stop):
        """func of data[start, stop)"""
        start += self._size
        stop += self._size

        res_left = res_right = self._default
        while start < stop:
            if start & 1:
                res_left = self._func(res_left, self.data[start])
                start += 1
            if stop & 1:
                stop -= 1
                res_right = self._func(self.data[stop], res_right)
            start >>= 1
            stop >>= 1

        return self._func(res_left, res_right)

    def __repr__(self):
        return "SegmentTree({0})".format(self.data)


import io
import os
from collections import defaultdict
from bisect import bisect_left, bisect_right


def solve(N, Q, C, LR):
    valToIndices = defaultdict(list)
    for i, c in enumerate(C):
        valToIndices[c].append(i)
    THRESHOLD = 500
    autoIncrement = defaultdict(lambda: len(autoIncrement))
    data = [0] * N
    for i, c in enumerate(C):
        if len(valToIndices[c]) < THRESHOLD:
            data[i] = 1 << autoIncrement[c]
    for k in list(valToIndices.keys()):
        if len(valToIndices[k]) < THRESHOLD:
            del valToIndices[k]
    segTree = SegmentTree(data, 0, lambda x, y: x | y)

    for l, r in LR:
        r += 1
        mask = segTree.query(l, r)
        lowFreqCount = 0
        while mask:
            lowFreqCount += mask & 1
            mask >>= 1
        highFreqCount = 0
        for x, indices in valToIndices.items():
            if bisect_right(indices, r - 1) - bisect_left(indices, l):
                highFreqCount += 1
        print(lowFreqCount + highFreqCount)


if __name__ == "__main__":
    input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline

    N, Q = [int(x) for x in input().split()]
    C = [int(x) for x in input().split()]
    LR = [[int(x) - 1 for x in input().split()] for i in range(Q)]  # 0-indexed
    solve(N, Q, C, LR)


### FIXED CODE ###

# From: https://github.com/cheran-senthil/PyRival/blob/master/pyrival/data_structures/SegmentTree.py
class SegmentTree:
    def __init__(self, data, default=0, func=max):
        """initialize the segment tree with data"""
        self._default = default
        self._func = func
        self._len = len(data)
        self._size = _size = 1 << (self._len - 1).bit_length()

        self.data = [default] * (2 * _size)
        self.data[_size : _size + self._len] = data
        for i in reversed(range(_size)):
            self.data[i] = func(self.data[i + i], self.data[i + i + 1])

    def __delitem__(self, idx):
        self[idx] = self._default

    def __getitem__(self, idx):
        return self.data[idx + self._size]

    def __setitem__(self, idx, value):
        idx += self._size
        self.data[idx] = value
        idx >>= 1
        while idx:
            self.data[idx] = self._func(self.data[2 * idx], self.data[2 * idx + 1])
            idx >>= 1

    def __len__(self):
        return self._len

    def query(self, start, stop):
        """func of data[start, stop)"""
        start += self._size
        stop += self._size

        res_left = res_right = self._default
        while start < stop:
            if start & 1:
                res_left = self._func(res_left, self.data[start])
                start += 1
            if stop & 1:
                stop -= 1
                res_right = self._func(self.data[stop], res_right)
            start >>= 1
            stop >>= 1

        return self._func(res_left, res_right)

    def __repr__(self):
        return "SegmentTree({0})".format(self.data)


import io
import os
from collections import defaultdict


def solve(N, Q, C, LR):
    # Bucket sort queries by right endpoint
    LByR = defaultdict(list)
    for i, (l, r) in enumerate(LR):
        LByR[r].append((i, l))

    # Segment tree stores a 1 at position i if the ith element is the rightmost of its dupes
    segTree = SegmentTree([0] * (N + 1), 0, lambda x, y: x + y)
    lastSeen = {}
    ans = [0] * Q
    for r, x in enumerate(C):
        if x in lastSeen:
            # Clear the previous rightmost bit
            segTree[lastSeen[x]] -= 1
        # Add a new rightmost bit
        segTree[r] += 1
        lastSeen[x] = r

        for queryIndex, l in LByR[r]:
            ans[queryIndex] = segTree.query(l, r + 1)

    return "\n".join(map(str, ans))


if __name__ == "__main__":
    input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline

    N, Q = [int(x) for x in input().split()]
    C = [int(x) for x in input().split()]
    # 0-indexed, inclusive inclusive
    LR = [[int(x) - 1 for x in input().split()] for i in range(Q)]
    print(solve(N, Q, C, LR))