Codeforces 86D 题解(莫队)
Description
给出一个长度为\(n\)数列\(a\),\(q\)次询问,每次询问为一个\([l,r]\)的区间,求区间内 每种数字出现次数的平方×数字的值 的和。
\(n,q \leq 2 \times 10^5, a_i \leq 10^6\)
Solution
看到只有询问没有修改,而且有\(a_i \leq 10^6\),那么我们可以使用莫队算法。
记一个now表示当前区间的答案,在区间伸长的时候加一下伸长的位置的答案,缩短的时候减一下缩短的位置的答案就好了。
Code
#include <algorithm>
#include <cstdio>
#include <cmath>
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define int long long
const int MAXN = 1e6 + 5;
int n, m, a[MAXN], cnt[MAXN], now, block, ans[MAXN], ql = 1, qr;
struct Query {int l, r, ser;} q[MAXN];
inline bool cmp(Query a, Query b) {
return (a.l / block == b.l / block) ? a.r < b.r : a.l < b.l;
}
inline void ADD(int pos) {
cnt[a[pos]]++; now += a[pos] * (2 * cnt[a[pos]] - 1);
}
inline void DEL(int pos) {
cnt[a[pos]]--; now -= a[pos] * (2 * cnt[a[pos]] + 1);
}
signed main() {
scanf("%lld %lld", &n, &m); block = std::sqrt(n);
rep(i, 1, n) scanf("%lld", &a[i]);
rep(i, 1, m) {
int l, r; scanf("%lld %lld", &l, &r);
q[i] = (Query) {l, r, i};
} std::sort(q + 1, q + m + 1, cmp);
rep(i, 1, m) {
int L = q[i].l, R = q[i].r;
while(ql < L) DEL(ql++); while(ql > L) ADD(--ql);
while(qr < R) ADD(++qr); while(qr > R) DEL(qr--);
ans[q[i].ser] = now;
} rep(i, 1, m) printf("%lld\n", ans[i]);
return 0;
}

浙公网安备 33010602011771号