题目链接 Powerful array
给你n个数,m次询问,Ks为区间内s的数目,求区间[L,R]之间所有Ks*Ks*s的和。
$1<=n,m<=200000, 1<=s<=10^{6}$
考虑莫队算法
把区间排序,然后让l和r分别询问即可。
根据排序的方式,l指针和r指针移动次数和大概是$n\sqrt{n}$ 级别的。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
typedef long long LL;
const int N = 2e5 + 10;
const int M = 1e6 + 10;
int belong[N];
struct query{
int l, r;
int id;
void scan(){ scanf("%d%d", &l, &r); }
friend bool operator < (const query &a, const query &b){
return belong[a.l] == belong[b.l] ? a.r < b.r :
belong[a.l] < belong[b.l];
}
} q[N];
int n, m;
int a[N], c[M];
int BS, l, r;
LL ret[N], ans;
int main(){
scanf("%d%d", &n, &m);
rep(i, 1, n) scanf("%d", a + i);
BS = sqrt(n);
rep(i, 1, n) belong[i] = (i - 1) / BS + 1;
rep(i, 1, m){
q[i].scan();
q[i].id = i;
}
sort(q + 1, q + m + 1);
l = 0; r = 0; ans = 0;
rep(i, 1, m){
while (l > q[i].l){
--l;
ans += (LL)(2 * c[a[l]] + 1) * a[l];
++c[a[l]];
}
while (r < q[i].r){
++r;
ans += (LL)(2 * c[a[r]] + 1) * a[r];
++c[a[r]];
}
while (l < q[i].l){
--c[a[l]];
ans -= (LL)(2 * c[a[l]] + 1) * a[l];
++l;
}
while (r > q[i].r){
--c[a[r]];
ans -= (LL)(2 * c[a[r]] + 1) * a[r];
--r;
}
ret[q[i].id] = ans;
}
rep(i, 1, m) printf("%lld\n", ret[i]);
return 0;
}