题目
传松门
题目描述
小B有一个序列,包含N个1~K之间的整数。他一共有M个询问,每个询问给定一个区间[L…R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L…R]中的重复次数。小B请你帮助他回答询问。
输入输出格式
输入格式:
第一行,三个整数N、M、K。
第二行,N个整数,表示小B的序列。
接下来的M行,每行两个整数L、R。
输出格式:
M行,每行一个整数,其中第i行的整数表示第i个询问的答案。
题解
- 莫队板子题
- 修改时
inline void add(int x) {
cnt[ a[x] ]++;
ans += cnt[ a[x] ] * 2 - 1;
}
inline void del(int x) {
cnt[ a[x] ]--;
ans -= cnt[ a[x] ] * 2 + 1;
}
上面修改自己手推一下应该就可以了,其实就是完全平方公式
code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e4 + 1000;
template <typename T>
inline void read(T &s) {
s = 0;
T w = 1, ch = getchar();
while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
s *= w;
}
int n, m, k, ans;
int a[maxn], pos[maxn], res[maxn], cnt[maxn];
struct query { int l, r, id; } q[maxn];
inline bool cmp(query A, query B) {
return (pos[A.l] == pos[B.l]) ? A.r < B.r : A.l < B.l;
}
inline void add(int x) {
cnt[ a[x] ]++;
ans += cnt[ a[x] ] * 2 - 1;
}
inline void del(int x) {
cnt[ a[x] ]--;
ans -= cnt[ a[x] ] * 2 + 1;
}
int main() {
read(n), read(m), read(k);
int blo = n / sqrt(m);
for (int i = 1; i <= n; ++i) {
read(a[i]);
pos[i] = (i - 1) / blo + 1;
}
for (int i = 1; i <= m; ++i) {
read(q[i].l), read(q[i].r);
q[i].id = i;
}
sort(q + 1, q + m + 1, cmp);
int l = 1, r = 0;
for (int i = 1; i <= m; ++i) {
int ql = q[i].l, qr = q[i].r;
while (l < ql) del(l++);
while (l > ql) add(--l);
while (r < qr) add(++r);
while (r > qr) del(r--);
res[ q[i].id ] = ans;
}
for (int i = 1; i <= m; ++i)
printf("%d\n", res[i]);
return 0;
}