// The main code is at the very bottom.

#[allow(unused_imports)]
use {
  lib::byte::ByteChar,
  std::cell::{Cell, RefCell},
  std::cmp::{
    self,
    Ordering::{self, *},
    Reverse,
  },
  std::collections::*,
  std::convert::identity,
  std::fmt::{self, Debug, Display, Formatter},
  std::io::prelude::*,
  std::iter::{self, FromIterator},
  std::marker::PhantomData,
  std::mem,
  std::num::Wrapping,
  std::ops::{Range, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive},
  std::process,
  std::rc::Rc,
  std::thread,
  std::time::{Duration, Instant},
  std::{char, f32, f64, i128, i16, i32, i64, i8, isize, str, u128, u16, u32, u64, u8, usize},
};

#[allow(unused_imports)]
#[macro_use]
pub mod lib {

  pub mod algebra {

    pub mod structures {

      pub use self::abelian_group::*;
      pub use self::associative_magma::*;
      pub use self::commutative_magma::*;
      pub use self::group::*;
      pub use self::invertible_magma::*;
      pub use self::magma::*;
      pub use self::monoid::*;
      pub use self::semigroup::*;
      pub use self::unital_magma::*;

      mod abelian_group {
        use super::{CommutativeMagma, Group};

        pub trait AbelianGroup: Group + CommutativeMagma {}

        impl<T: Group + CommutativeMagma> AbelianGroup for T {}
      }
      mod associative_magma {
        use super::Magma;

        pub trait AssociativeMagma: Magma {}

        impl AssociativeMagma for () {}

        impl<T> AssociativeMagma for Option<T> where T: AssociativeMagma {}
      }
      mod commutative_magma {
        use super::Magma;

        pub trait CommutativeMagma: Magma {}

        impl CommutativeMagma for () {}

        impl<T> CommutativeMagma for Option<T> where T: CommutativeMagma {}
      }
      mod group {
        use super::{AssociativeMagma, InvertibleMagma, UnitalMagma};

        pub trait Group: AssociativeMagma + UnitalMagma + InvertibleMagma {}

        impl<T: AssociativeMagma + UnitalMagma + InvertibleMagma> Group for T {}
      }
      mod invertible_magma {
        use super::{Magma, UnitalMagma};

        pub trait InvertibleMagma: Magma + UnitalMagma {
          fn invert(&self) -> Self;

          fn inverse_op(&self, rhs: &Self) -> Self {
            self.op(&rhs.invert())
          }

          fn inverse_op_assign_right(&mut self, rhs: &Self) {
            *self = self.inverse_op(rhs);
          }

          fn inverse_op_assign_left(&mut self, lhs: &Self) {
            *self = lhs.inverse_op(self);
          }
        }

        impl InvertibleMagma for () {
          #[allow(clippy::unused_unit)]
          fn invert(&self) -> Self {
            ()
          }
        }
      }
      mod magma {

        pub trait Magma: Clone {
          fn op(&self, rhs: &Self) -> Self;

          fn op_assign_right(&mut self, rhs: &Self) {
            *self = self.op(rhs);
          }

          fn op_assign_left(&mut self, lhs: &Self) {
            *self = lhs.op(self);
          }
        }

        impl Magma for () {
          #[allow(clippy::unused_unit)]
          fn op(&self, _rhs: &Self) -> Self {
            ()
          }
        }

        impl<T> Magma for Option<T>
        where
          T: Magma,
        {
          fn op(&self, rhs: &Self) -> Self {
            match (self, rhs) {
              (Some(lhs), Some(rhs)) => Some(lhs.op(rhs)),
              (Some(x), None) | (None, Some(x)) => Some(x.clone()),
              (None, None) => None,
            }
          }
        }
      }
      mod monoid {
        use super::{AssociativeMagma, UnitalMagma};

        pub trait Monoid: AssociativeMagma + UnitalMagma {}

        impl<T: AssociativeMagma + UnitalMagma> Monoid for T {}
      }
      mod semigroup {
        use super::AssociativeMagma;

        pub trait Semigroup: AssociativeMagma {}

        impl<T: AssociativeMagma> Semigroup for T {}
      }
      mod unital_magma {
        use super::Magma;

        pub trait UnitalMagma: Magma {
          fn identity() -> Self;
        }

        impl UnitalMagma for () {
          #[allow(clippy::unused_unit)]
          fn identity() -> Self {
            ()
          }
        }

        impl<T> UnitalMagma for Option<T>
        where
          T: Magma,
        {
          fn identity() -> Self {
            None
          }
        }
      }
    }
  }
  pub mod byte {

    pub use self::byte_char::*;

    mod byte_char {
      use std::error::Error;
      use std::fmt::{self, Debug, Display, Formatter};
      use std::str::FromStr;

      #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
      #[repr(transparent)]
      pub struct ByteChar(pub u8);

      impl Debug for ByteChar {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          write!(f, "b'{}'", self.0 as char)
        }
      }

      impl Display for ByteChar {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          write!(f, "{}", self.0 as char)
        }
      }

      impl FromStr for ByteChar {
        type Err = ParseByteCharError;

        fn from_str(s: &str) -> Result<ByteChar, ParseByteCharError> {
          match s.as_bytes().len() {
            1 => Ok(ByteChar(s.as_bytes()[0])),
            0 => Err(ParseByteCharErrorKind::EmptyStr.into()),
            _ => Err(ParseByteCharErrorKind::TooManyBytes.into()),
          }
        }
      }

      #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
      pub struct ParseByteCharError {
        kind: ParseByteCharErrorKind,
      }

      impl Display for ParseByteCharError {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          f.write_str(match self.kind {
            ParseByteCharErrorKind::EmptyStr => "empty string",
            ParseByteCharErrorKind::TooManyBytes => "too many bytes",
          })
        }
      }

      impl Error for ParseByteCharError {}

      #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
      enum ParseByteCharErrorKind {
        EmptyStr,
        TooManyBytes,
      }

      impl From<ParseByteCharErrorKind> for ParseByteCharError {
        fn from(kind: ParseByteCharErrorKind) -> ParseByteCharError {
          ParseByteCharError { kind }
        }
      }
    }
  }

  pub mod io {

    pub use self::scanner::*;

    mod scanner {
      use std::io::{self, BufRead};
      use std::str::FromStr;

      #[derive(Debug)]
      pub struct Scanner<R> {
        reader: R,
        buf: String,
        pos: usize,
      }

      impl<R: BufRead> Scanner<R> {
        pub fn new(reader: R) -> Self {
          Scanner {
            reader,
            buf: String::new(),
            pos: 0,
          }
        }

        pub fn next(&mut self) -> io::Result<&str> {
          let start = loop {
            match self.rest().find(|c| c != ' ') {
              Some(i) => break i,
              None => self.fill_buf()?,
            }
          };
          self.pos += start;
          let len = self.rest().find(' ').unwrap_or_else(|| self.rest().len());
          let s = &self.buf[self.pos..][..len]; // self.rest()[..len]
          self.pos += len;
          Ok(s)
        }

        pub fn parse_next<T>(&mut self) -> io::Result<Result<T, T::Err>>
        where
          T: FromStr,
        {
          Ok(self.next()?.parse())
        }

        pub fn parse_next_n<T>(&mut self, n: usize) -> io::Result<Result<Vec<T>, T::Err>>
        where
          T: FromStr,
        {
          std::iter::repeat_with(|| self.parse_next())
            .take(n)
            .collect()
        }

        pub fn map_next_bytes<T, F>(&mut self, mut f: F) -> io::Result<Vec<T>>
        where
          F: FnMut(u8) -> T,
        {
          Ok(self.next()?.bytes().map(&mut f).collect())
        }

        pub fn map_next_bytes_n<T, F>(&mut self, n: usize, mut f: F) -> io::Result<Vec<Vec<T>>>
        where
          F: FnMut(u8) -> T,
        {
          std::iter::repeat_with(|| self.map_next_bytes(&mut f))
            .take(n)
            .collect()
        }

        fn rest(&self) -> &str {
          &self.buf[self.pos..]
        }

        fn fill_buf(&mut self) -> io::Result<()> {
          self.buf.clear();
          self.pos = 0;
          let read = self.reader.read_line(&mut self.buf)?;
          if read == 0 {
            return Err(io::ErrorKind::UnexpectedEof.into());
          }
          if *self.buf.as_bytes().last().unwrap() == b'\n' {
            self.buf.pop();
          }
          Ok(())
        }
      }
    }
  }

  pub mod sequences {

    pub use self::fenwick_tree::FenwickTree;

    pub mod fenwick_tree {

      use super::super::algebra::structures::{AbelianGroup, CommutativeMagma, Monoid};
      use super::super::utils::index_bounds_check::*;

      use std::iter::FromIterator;
      use std::ops::{Range, RangeTo};

      #[derive(Clone, PartialEq, Eq, Debug, Hash)]
      pub struct FenwickTree<T> {
        vec: Vec<T>,
      }

      impl<M: Monoid + CommutativeMagma> FenwickTree<M> {
        pub fn new(len: usize) -> Self {
          FenwickTree {
            vec: vec![M::identity(); len],
          }
        }

        pub fn len(&self) -> usize {
          self.vec.len()
        }

        pub fn point_append(&mut self, index: usize, value: &M) {
          assert_index(index, self.len());

          // 0-based => 1-based
          let mut node = index + 1;

          while node <= self.len() {
            self.node_mut(node).op_assign_right(value);
            node += lsb(node);
          }
        }

        pub fn prefix_fold(&self, index: RangeTo<usize>) -> M {
          assert_index_range_to(index, self.len());

          // 0-based [0, e) => 1-based [1, e + 1) => 1-based [1, e]
          let mut end = index.end;

          let mut acc = M::identity();

          while end > 0 {
            acc.op_assign_right(self.node(end));
            end -= lsb(end);
          }

          acc
        }

        fn node(&self, node: usize) -> &M {
          &self.vec[node - 1]
        }

        fn node_mut(&mut self, node: usize) -> &mut M {
          &mut self.vec[node - 1]
        }
      }

      impl<G: AbelianGroup> FenwickTree<G> {
        pub fn get(&self, index: usize) -> G {
          assert_index(index, self.len());

          self.fold(index..index + 1)
        }

        pub fn replace(&mut self, index: usize, value: &G) -> G {
          let old_value = self.get(index);
          self.point_append(index, &value.inverse_op(&old_value));
          old_value
        }

        pub fn fold(&self, index: Range<usize>) -> G {
          assert_index_range(&index, self.len());

          // 0-based [s, e) => 1-based [s + 1, e + 1) => 1-based (s, e]
          let mut start = index.start;
          let mut end = index.end;

          let mut acc = G::identity();

          while start < end {
            acc.op_assign_right(self.node(end));
            end -= lsb(end);
          }

          while end < start {
            acc.inverse_op_assign_right(self.node(start));
            start -= lsb(start);
          }

          acc
        }
      }

      impl<M: Monoid + CommutativeMagma> From<Vec<M>> for FenwickTree<M> {
        fn from(mut vec: Vec<M>) -> Self {
          vec.shrink_to_fit();
          let mut tree = FenwickTree { vec };

          // the last element (`tree.node(tree.len())`) does not have a parent
          for node in 1..tree.len() {
            let parent = node + lsb(node);

            if parent <= tree.len() {
              *tree.node_mut(parent) = tree.node(parent).op(&tree.node(node));
            }
          }

          tree
        }
      }

      impl<M: Monoid + CommutativeMagma> FromIterator<M> for FenwickTree<M> {
        fn from_iter<I>(iter: I) -> Self
        where
          I: IntoIterator<Item = M>,
        {
          Self::from(iter.into_iter().collect::<Vec<_>>())
        }
      }

      // least significant bit
      fn lsb(x: usize) -> usize {
        debug_assert_ne!(x, 0);
        x & (!x + 1)
      }
    }
  }
  mod utils {
    pub mod index_bounds_check {
      use std::ops::{Range, RangeTo};

      macro_rules! assert_index {
        ($cond:expr, $index:expr, $len:expr) => {
          assert!(
            $cond,
            "index out of bounds: the len is {:?} but the index is {:?}",
            $len, $index
          )
        };
      }

      pub fn assert_index(index: usize, len: usize) {
        assert_index!(index < len, index, len);
      }

      pub fn assert_index_range_to(index: RangeTo<usize>, len: usize) {
        assert_index!(index.end <= len, index, len);
      }

      pub fn assert_index_range(index: &Range<usize>, len: usize) {
        assert!(
          index.start <= index.end,
          "range start is greater than range end: {:?}",
          index
        );
        assert_index!(index.end <= len, index, len);
      }
    }
  }
}

#[allow(unused_macros)]
macro_rules! eprint {
  ($($arg:tt)*) => {
    if cfg!(debug_assertions) {
      std::eprint!($($arg)*)
    }
  };
}
#[allow(unused_macros)]
macro_rules! eprintln {
  ($($arg:tt)*) => {
    if cfg!(debug_assertions) {
      std::eprintln!($($arg)*)
    }
  };
}
#[allow(unused_macros)]
macro_rules! dbg {
  ($($arg:tt)*) => {
    if cfg!(debug_assertions) {
      std::dbg!($($arg)*)
    } else {
      ($($arg)*)
    }
  };
}

const CUSTOM_STACK_SIZE_MIB: Option<usize> = Some(128);
const INTERACTIVE: bool = false;

fn main() -> std::io::Result<()> {
  match CUSTOM_STACK_SIZE_MIB {
    Some(stack_size_mib) => std::thread::Builder::new()
      .name("run_solver".to_owned())
      .stack_size(stack_size_mib * 1024 * 1024)
      .spawn(run_solver)?
      .join()
      .unwrap(),
    None => run_solver(),
  }
}

fn run_solver() -> std::io::Result<()> {
  let stdin = std::io::stdin();
  let reader = stdin.lock();
  let stdout = std::io::stdout();
  let writer = stdout.lock();
  macro_rules! with_wrapper {
    ($($wrapper:expr)?) => {{
      let mut writer = $($wrapper)?(writer);
      solve(reader, &mut writer)?;
      writer.flush()
    }};
  }
  if cfg!(debug_assertions) || INTERACTIVE {
    with_wrapper!()
  } else {
    with_wrapper!(std::io::BufWriter::new)
  }
}

fn solve<R, W>(reader: R, mut writer: W) -> std::io::Result<()>
where
  R: BufRead,
  W: Write,
{
  let mut _scanner = lib::io::Scanner::new(reader);
  #[allow(unused_macros)]
  macro_rules! scan {
    ($T:ty) => {
      _scanner.parse_next::<$T>()?.unwrap()
    };
    ($($T:ty),+) => {
      ($(scan!($T)),+)
    };
    ($T:ty; $n:expr) => {
      _scanner.parse_next_n::<$T>($n)?.unwrap()
    };
    ($($T:ty),+; $n:expr) => {
      iter::repeat_with(|| -> std::io::Result<_> { Ok(($(scan!($T)),+)) })
        .take($n)
        .collect::<std::io::Result<Vec<_>>>()?
    };
  }
  #[allow(unused_macros)]
  macro_rules! scan_bytes_map {
    ($f:expr) => {
      _scanner.map_next_bytes($f)?
    };
    ($f:expr; $n:expr) => {
      _scanner.map_next_bytes_n($n, $f)?
    };
  }
  #[allow(unused_macros)]
  macro_rules! print {
    ($($arg:tt)*) => {
      write!(writer, $($arg)*)?
    };
  }
  #[allow(unused_macros)]
  macro_rules! println {
    ($($arg:tt)*) => {
      writeln!(writer, $($arg)*)?
    };
  }
  #[allow(unused_macros)]
  macro_rules! answer {
    ($($arg:tt)*) => {{
      println!($($arg)*);
      return Ok(());
    }};
  }
  {
    use lib::{algebra::structures::*, sequences::*};

    #[derive(Clone, Copy, PartialEq, Eq, Debug)]
    pub struct Sum(pub i64);

    impl Magma for Sum {
      fn op(&self, rhs: &Self) -> Self {
        Sum(self.0 + rhs.0)
      }
    }

    impl AssociativeMagma for Sum {}

    impl CommutativeMagma for Sum {}

    impl UnitalMagma for Sum {
      fn identity() -> Self {
        Sum(0)
      }
    }

    impl InvertibleMagma for Sum {
      fn invert(&self) -> Self {
        Sum(-self.0)
      }
    }

    let (n, q) = scan!(usize, usize);
    let c = scan!(usize; n)
      .into_iter()
      .map(|c_i| c_i - 1)
      .collect::<Vec<_>>();

    let mut queries = scan!(usize, usize; q)
      .into_iter()
      .enumerate()
      .map(|(i, (l, r))| (i, (l - 1, r - 1)))
      .collect::<Vec<_>>();
    queries.sort_unstable_by_key(|&(_, (_, r))| r);

    let mut ft = FenwickTree::<Sum>::new(n);
    let mut a = vec![None; n];
    let mut prev_r = None;
    let mut ans = vec![None; q];
    for (i, (l, r)) in queries {
      for i in prev_r.map_or(0, |pr| pr + 1)..=r {
        if let Some(x) = a[c[i]] {
          ft.point_append(x, &Sum(-1));
        }
        a[c[i]] = Some(i);
        ft.point_append(i, &Sum(1));
      }
      ans[i] = Some(ft.fold(l..r + 1).0);
      prev_r = Some(r);
    }
    for ans in ans {
      println!("{}", ans.unwrap());
    }
  }
  #[allow(unreachable_code)]
  Ok(())
}


Measured memory_bytes: 39396