Description
给定一个数列,有若干个询问,每次给定一个区间,问这个数列区间中,所有不同数的值乘以它的出现次数平方的和是多少。数的大小不超过 (10^6)。
Solution
莫队,对于数 (a),其出现次数从 (x o x+1) 时,答案增加了 ((2x+1)a)。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1000005;
int n, t, a[N], cnt[N], ans;
void add(int i)
{
ans += a[i] * (cnt[a[i]] * 2 + 1);
cnt[a[i]]++;
}
void dec(int i)
{
cnt[a[i]]--;
ans -= a[i] * (cnt[a[i]] * 2 + 1);
}
int pl, pr;
void adjust(int ql, int qr)
{
while (pr < qr)
{
++pr;
add(pr);
}
while (pl > ql)
{
--pl;
add(pl);
}
while (pr > qr)
{
dec(pr);
--pr;
}
while (pl < ql)
{
dec(pl);
++pl;
}
}
int bel[N], res[N];
struct range
{
int l, r, id;
bool operator<(const range &b)
{
return bel[l] == bel[b.l] ? r < b.r : l < b.l;
}
} ran[N];
signed main()
{
ios::sync_with_stdio(false);
cin >> n >> t;
int sq = sqrt(n);
for (int i = 1; i <= n; i++)
bel[i] = i / sq + 1;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= t; i++)
cin >> ran[i].l >> ran[i].r, ran[i].id = i;
sort(ran + 1, ran + t + 1);
pl = 1;
pr = 0;
for (int i = 1; i <= t; i++)
{
adjust(ran[i].l, ran[i].r);
res[ran[i].id] = ans;
}
for (int i = 1; i <= t; i++)
cout << res[i] << endl;
}