#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
// Đặt giới hạn và kích thước khối
const int MAXN = 100005;
const int BLOCK_SIZE = 320; // Khoảng căn bậc hai của N
// Giá trị tối đa của a[i] là 10^6, cần nén hoặc dùng mảng lớn
// Ở đây ta dùng mảng Count/SumIndex với kích thước đủ lớn,
// nếu giá trị a[i] quá lớn, cần Rời rạc hóa (Coordinate Compression)
// Mảng để lưu trữ giá trị nén/gốc của a[i]
vector<int> a;
// Cấu trúc dữ liệu hỗ trợ Mo's (1-based indexing cho a[i])
// F_current: Giá trị F(l, r) hiện tại
long long F_current = 0;
// TotalElements: Số lượng phần tử hiện tại trong đoạn [current_l, current_r] (dùng cho công thức Delta)
long long TotalElements = 0;
// TotalSumIndex: Tổng các chỉ số hiện tại trong đoạn [current_l, current_r] (dùng cho công thức Delta)
long long TotalSumIndex = 0;
// Mảng thống kê tần suất và tổng chỉ số
// Sử dụng map hoặc nén tọa độ nếu a[i] > 10^5.
// Giả định giá trị a[i] đã được nén nếu cần, hoặc ta dùng mảng đủ lớn (ví dụ: MAX_A=10^6)
// Tuy nhiên, để đơn giản và phù hợp với giới hạn bộ nhớ CP, ta sẽ dùng mảng cho a[i] (giả sử đã nén/giá trị không quá 10^5)
// Để tránh lỗi TLE/MLE, ta sẽ dùng mảng lớn và dựa vào thực tế là chỉ có N giá trị phân biệt.
const int MAX_VAL = 1000001; // Giả sử max a[i] là 10^6
int Count[MAX_VAL] = {0}; // Tần suất của giá trị a[i] trong đoạn [l+1, r] (cho Delta)
long long SumIndex[MAX_VAL] = {0}; // Tổng chỉ số i mà a[i] = v trong đoạn [l+1, r]
// Cấu trúc cho truy vấn
struct Query {
int l, r, index;
int block_l;
bool operator<(const Query& other) const {
if (block_l != other.block_l) {
return block_l < other.block_l;
}
// Tối ưu hóa Zizag
if (block_l % 2 == 0) {
return r < other.r;
}
return r > other.r;
}
};
// --- Hàm Cập Nhật Mo's Algorithm (Độ phức tạp O(1)) ---
// Cập nhật Count và SumIndex khi thêm/bớt a[idx]
void update_stats_add(int idx) {
Count[a[idx]]++;
SumIndex[a[idx]] += idx;
TotalElements++;
TotalSumIndex += idx;
}
void update_stats_remove(int idx) {
Count[a[idx]]--;
SumIndex[a[idx]] -= idx;
TotalElements--;
TotalSumIndex -= idx;
}
// 1. Cập nhật khi r tăng (r -> r+1). Ta cần tính Delta F_r
// Delta F_r = sum_{j=l}^{r} G(l, j) + G(l, r+1)
// G(l, j) = sum_{k=0}^{j-l} [a_j != a_{l+k}]
// Vẫn là một phép tính phức tạp. Quay lại công thức F(l, r) rút gọn:
// F(l, r) = sum_{j=l}^{r} (r - j + 1) * G(l, j)
void add_r(int new_r, int current_l) {
// F(l, r+1) = sum_{j=l}^{r+1} (r+1 - j + 1) * G(l, j)
// F(l, r) = sum_{j=l}^{r} (r - j + 1) * G(l, j)
// Delta F_r = F(l, r+1) - F(l, r)
// = [sum_{j=l}^{r} G(l, j)] + [(r+1 - (r+1) + 1) * G(l, r+1)]
// = [sum_{j=l}^{r} G(l, j)] + G(l, r+1)
// G(l, j) là tổng [a_j != a_i] với i thuộc [l, j].
// G(l, j) = (j - l + 1) - (số lần a_j xuất hiện trong a[l..j])
// Tính G(l, r+1)
int len_new = new_r - current_l + 1;
// Cập nhật F_current dựa trên sự thay đổi hệ số cho j in [current_l, new_r-1]
// Và thêm đóng góp của j = new_r.
// Bước 1: Duy trì Tổng [sum_{j=l}^{r} G(l, j)] (Đây là cái ta cần duy trì)
// Để tối ưu, ta cần duy trì một mảng/biến phụ trợ.
// Nếu không, ta phải lặp O(N) lần => TLE.
// Đây là phần khó nhất: Cập nhật tổng G(l, j) một cách hiệu quả.
// Với mục tiêu là code AC, ta cần chấp nhận rằng Mo's with O(1) update cho bài này
// là cực kỳ phức tạp. Ta sẽ dùng tối ưu hóa cho hàm remove_l (công thức Delta đơn giản)
// và cố gắng tối ưu hàm add_r.
// Vì hàm add_r vẫn phức tạp, ta sẽ dùng cách đơn giản hóa:
// Tổng của [sum_{j=l}^{r} G(l, j)] được tính bằng cách duy trì một biến tổng phụ.
// THAY THẾ: Vì không thể duy trì tổng G(l, j) một cách O(1) khi l thay đổi,
// ta phải chấp nhận độ phức tạp cao hơn cho add_r/remove_r.
// Tuy nhiên, việc tối ưu hóa remove_l vẫn giữ nguyên:
// THÍCH NGHI:
// Ta sử dụng công thức Delta đơn giản (phân tích) cho remove_l.
// Ta sử dụng O(N) cho add_r/remove_r. Tổng: O(N * (N*sqrt(N))) -> Vẫn TLE.
// => Giải pháp là Mo's trên Mảng/Lược đồ. (Quá phức tạp để code trực tiếp)
// Ta trở lại với giả định ban đầu: Ta phải dùng công thức Delta đã tối ưu:
// Cần phải duy trì: total_G_sum = sum_{j=l}^{r} G(l, j)
// Khi r -> r+1: total_G_sum += G(l, r+1)
// F_current = F_current + total_G_sum + G(l, r+1)
// Ta cần một biến để tính G(l, j) = (j - l + 1) - count_a_j_in_[l, j]
// Đây là nơi cần một cấu trúc dữ liệu!
// *Bỏ qua sự duy trì tổng G(l, j) và chỉ tập trung vào remove_l (đơn giản nhất)
}
void remove_r(int old_r, int current_l) {
// Ngược lại add_r.
}
// 2. Cập nhật khi l tăng (l -> l+1). Ta cần tính Delta F_l
// Delta F_l = - sum_{j=l+1}^{r} (r - j + 1) * [a_j != a_l] (Công thức đã tối ưu)
void remove_l(int old_l, int current_r) {
// old_l là chỉ số bị loại bỏ.
int val_old_l = a[old_l];
// 1. Tính Delta F_l (phần thay đổi của tổng cũ)
// Delta F_l = - ( (r+1) * Sum([a_j != a_l]) - Sum(j * [a_j != a_l]) )
// Tính trong đoạn [old_l+1, current_r] (đoạn mới):
// Tổng số phần tử trong đoạn mới: TotalElements - 1
// Tổng chỉ số: TotalSumIndex - old_l
// Số lần a_l xuất hiện trong đoạn [old_l+1, current_r]: Count[val_old_l] - 1
// Tổng chỉ số của a_l trong đoạn [old_l+1, current_r]: SumIndex[val_old_l] - old_l
// Tính Sum([a_j != a_l]):
long long count_not_equal = (TotalElements - 1) - (Count[val_old_l] - 1);
// Tính Sum(j * [a_j != a_l]):
long long sum_index_not_equal = (TotalSumIndex - old_l) - (SumIndex[val_old_l] - old_l);
// Delta F_l
long long delta_F_l = -( (long long)(current_r + 1) * count_not_equal - sum_index_not_equal );
F_current += delta_F_l;
// 2. Cập nhật thống kê (a[old_l] bị loại khỏi đoạn [l, r])
update_stats_remove(old_l); // Cập nhật Count/SumIndex cho đoạn mới [old_l+1, current_r]
}
// 3. Cập nhật khi l giảm (l -> l-1)
// Delta F_l = F(l-1, r) - F(l, r)
// = - (r - (l-1) + 1) * G(l-1, l-1) - sum_{j=l}^{r} (r-j+1) * [a_j != a_{l-1}]
// = - sum_{j=l}^{r} (r-j+1) * [a_j != a_{l-1}]
// => Delta F_l = -(Delta F_l khi l tăng, nhưng với a_{l-1} thay vì a_l)
void add_l(int new_l, int current_r) {
// 1. Cập nhật thống kê (a[new_l] được thêm vào đoạn [new_l, current_r])
update_stats_add(new_l);
int val_new_l = a[new_l];
// 2. Tính Delta F_l (phần thay đổi của tổng cũ)
// Delta F_l = - sum_{j=new_l+1}^{current_r} (current_r - j + 1) * [a_j != a_{new_l}]
// Tính trong đoạn [new_l+1, current_r] (đoạn mới):
// Số lần a_l xuất hiện trong đoạn [new_l+1, current_r]: Count[val_new_l] - 1 (vì ta đã gọi update_stats_add(new_l))
// Tổng chỉ số của a_l trong đoạn [new_l+1, current_r]: SumIndex[val_new_l] - new_l
// Tính Sum([a_j != a_{new_l}]):
long long count_not_equal = (TotalElements - 1) - (Count[val_new_l] - 1);
// Tính Sum(j * [a_j != a_{new_l}]):
long long sum_index_not_equal = (TotalSumIndex - new_l) - (SumIndex[val_new_l] - new_l);
// Delta F_l
long long delta_F_l = -( (long long)(current_r + 1) * count_not_equal - sum_index_not_equal );
F_current += delta_F_l;
}
// --- Hàm Chính ---
void solve() {
int N_int, Q_int;
cin >> N_int >> Q_int;
long long N = N_int, Q = Q_int;
a.resize(N + 1); // Dùng 1-based indexing
for (int i = 1; i <= N; ++i) {
cin >> a[i];
}
vector<Query> queries(Q);
for (int i = 0; i < Q; ++i) {
cin >> queries[i].l >> queries[i].r;
queries[i].index = i;
queries[i].block_l = queries[i].l / BLOCK_SIZE;
}
sort(queries.begin(), queries.end());
vector<long long> results(Q);
int current_l = 1;
int current_r = 0; // Để đoạn ban đầu là rỗng
// KHỞI TẠO BAN ĐẦU (Đoạn [1, 0] là rỗng)
// Xử lý từng truy vấn
for (const auto& q : queries) {
// Di chuyển con trỏ r (Phần O(N) chậm)
while (current_r < q.r) {
current_r++;
// Phải dùng phiên bản cập nhật O(N) cho r
// => Cần tối ưu add_r/remove_r tương tự add_l/remove_l
// Vì phức tạp, ta chấp nhận rằng phần này cũng cần tối ưu qua công thức!
}
while (current_r > q.r) {
// Phải dùng phiên bản cập nhật O(N) cho r
current_r--;
}
// Di chuyển con trỏ l (Phần O(1) đã tối ưu)
while (current_l < q.l) {
remove_l(current_l, current_r);
current_l++;
}
while (current_l > q.l) {
current_l--;
add_l(current_l, current_r);
}
results[q.index] = F_current;
}
// In kết quả
for (long long res : results) {
cout << res << "\n";
}
}
int main() {
// Tăng tốc độ I/O
ios_base::sync_with_stdio(false);
cin.tie(NULL);
// solve(); // Không thể chạy vì add_r/remove_r chưa được tối ưu
return 0;
}