题目描述
小sun最近突然对区间来了兴趣,现在他有这样一个问题想问问你:
给你n个数,每个数为aia_iai,现在有m个询问,每个询问l,r,需要求出:
∑i=lrai∗num(ai)\sum_{i=l}^r a_i*num(a_i)∑i=lrai∗num(ai)
num(ai)num(a_i)num(ai)代表aia_iai在这个区间中出现的次数。
你能帮帮他吗?
输入描述:
第一行,两个整数n,m
第二行,总共n个数,代表这个数列
接下来m行,每行两个整数l,r,代表一个询问
输出描述:
输出总共m行,对于每个询问,输出这个询问对应的答案
示例1
输入
复制
10 5
1 3 2 4 5 6 4 5 6 7
1 5
2 5
3 4
1 10
3 7
输出
复制
15
14
6
73
29
题目大意 : 输入长度为 N 的序列, M次询问, 每次问从 L 到 R当中, a【i】 * (a【i】的出现次数)之和
思路 : 很裸的莫队, 每次扩大区间时, 减去上一次更新的值, 再加上当前更新的某个数的出现次数的平方就好, 这个结论不难推
Accepted code
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
#define sc scanf
#define ls rt << 1
#define rs ls | 1
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define MEM(x, b) memset(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))
typedef long long ll;
const int MOD = 1e9 + 7;
const int MAXN = 2e5 + 100;
const int INF = 0x3f3f3f3f;
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % MOD; b >>= 1; t = (t*t) % MOD; }return r; }
struct node
{
int l, r, x;
}e[MAXN << 1];
int p[MAXN], belong[MAXN], n, m;
int num[MAXN], sum, L = 1, R;
ll pre[MAXN], ans;
bool cmp(node a, node b) { // 分块排序
if (belong[a.l] == belong[b.l]) return a.r < b.r;
return belong[a.l] < belong[b.l];
}
void add(int x) {
ans -= num[p[x]] * num[p[x]] * p[x];
num[p[x]]++, ans += num[p[x]] * num[p[x]] * p[x];
}
void del(int x){
ans -= num[p[x]] * num[p[x]] * p[x];
num[p[x]]--, ans += num[p[x]] * num[p[x]] * p[x];
}
int main()
{
cin >> n >> m; sum = sqrt(n);
int sz = ((double)n / sum);
for (int i = 1; i <= sz; i++) {
for (int j = (i - 1) * sum + 1; j <= i * sum; j++)
belong[j] = i;
}
for (int i = 1; i <= n; i++) sc("%d", &p[i]);
for (int i = 0; i < m; i++) sc("%d %d", &e[i].l, &e[i].r), e[i].x = i;
sort(e, e + m, cmp);
for (int i = 0; i < m; i++) {
int l = e[i].l, r = e[i].r, id = e[i].x;
while (L < l) del(L++);
while (L > l) add(--L);
while (R < r) add(++R);
while (R > r) del(R--);
pre[id] = ans;
}
for (int i = 0; i < m; i++) printf("%lld\n", pre[i]);
return 0;
}