Эффективная обработка запросов на отрезке в оффлайн режиме
n, t = map(int, input().split())
A = list(map(int, input().split()))
Q = [0] * t
c = int(n ** 0.5 + 1)
C = [[] for _ in range(c)]
for i in range(t):
l, r = map(int, input().split())
C[l // c].append([l - 1, r - 1, i])
for H in C:
if not H: continue
H.sort(key=lambda x: (x[1], x[0], x[2]))
z = 0
l, r, _ = H[0]
D = [0] * (10**6)
for i in range(l, r + 1):
z -= D[A[i]] * D[A[i]] * A[i]
D[A[i]] += 1
z += D[A[i]] * D[A[i]] * A[i]
for l1, r1, q in H:
while l1 < l:
l -= 1
i = l
z -= D[A[i]] * D[A[i]] * A[i]
D[A[i]] += 1
z += D[A[i]] * D[A[i]] * A[i]
while l1 > l:
i = l
z -= D[A[i]] * D[A[i]] * A[i]
D[A[i]] -= 1
z += D[A[i]] * D[A[i]] * A[i]
l += 1
while r1 < r:
i = r
z -= D[A[i]] * D[A[i]] * A[i]
D[A[i]] -= 1
z += D[A[i]] * D[A[i]] * A[i]
r -= 1
while r1 > r:
r += 1
i = r
z -= D[A[i]] * D[A[i]] * A[i]
D[A[i]] += 1
z += D[A[i]] * D[A[i]] * A[i]
Q[q] = z
print(*Q, sep="\n")
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAXV = 1e6 + 5;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
int n, t;
cin >> n >> t;
vector<int> A(n);
for (int i = 0; i < n; i++) {
cin >> A[i];
}
int c = sqrt(n) + 1;
vector<vector<tuple<int, int, int>>> C(c);
for (int i = 0; i < t; i++) {
int l, r;
cin >> l >> r;
l--; r--;
C[l / c].emplace_back(l, r, i);
}
vector<ll> Q(t);
vector<ll> D(MAXV, 0);
for (auto& H : C) {
if (H.empty()) continue;
sort(H.begin(), H.end(), [](const auto& a, const auto& b) {
if (get<1>(a) != get<1>(b)) return get<1>(a) < get<1>(b);
if (get<0>(a) != get<0>(b)) return get<0>(a) < get<0>(b);
return get<2>(a) < get<2>(b);
});
ll z = 0;
int l = get<0>(H[0]);
int r = get<1>(H[0]);
for (int i = l; i <= r; i++) {
z -= D[A[i]] * D[A[i]] * A[i];
D[A[i]]++;
z += D[A[i]] * D[A[i]] * A[i];
}
for (auto [l1, r1, q] : H) {
while (l1 < l) {
l--;
int i = l;
z -= D[A[i]] * D[A[i]] * A[i];
D[A[i]]++;
z += D[A[i]] * D[A[i]] * A[i];
}
while (l1 > l) {
int i = l;
z -= D[A[i]] * D[A[i]] * A[i];
D[A[i]]--;
z += D[A[i]] * D[A[i]] * A[i];
l++;
}
while (r1 < r) {
int i = r;
z -= D[A[i]] * D[A[i]] * A[i];
D[A[i]]--;
z += D[A[i]] * D[A[i]] * A[i];
r--;
}
while (r1 > r) {
r++;
int i = r;
z -= D[A[i]] * D[A[i]] * A[i];
D[A[i]]++;
z += D[A[i]] * D[A[i]] * A[i];
}
Q[q] = z;
}
}
for (int i = 0; i < t; i++) {
cout << Q[i] << "\n";
}
return 0;
}
Алгоритм Мо — это метод обработки запросов на отрезке в оффлайн режиме. Он особенно эффективен, когда ответ на запрос можно быстро пересчитать при добавлении или удалении граничного элемента.
Каждый запрос требует O(√n) перемещений левой границы и O(n) суммарно правой границы на блок. Общая сложность: O((n + q) × √n).
Ввод:
n t — количество элементов и количество запросовa1 a2 ... an — массив чиселl r — отрезок [l, r] (1-индексация)Вывод:
5 3
1 2 1 2 3
1 5
2 4
1 3
Вывод:
23
10
8
Пояснение:
[1,5]: 1(2 раза: 2²×1=4), 2(2 раза: 4×2=8), 3(1 раз: 1×3=3) → 4+8+3=15? Поправим.
Введите массив и запросы: