题目来源:Codeforces 86D
翻译:
描述
给出一个正整数序列 a1, a2, ..., an 。 我们考虑它的子序列 al, al+1..., ar ,其中 1≤l≤r≤n 。 Ks 表示数字 s 在序列中出现的次数。我们把一个序列的权值记作:
你需要计算t组询问。
输入
第一行包含两个整数
N
和
第二行包含
N
个正整数
接下来
T
行,每行包含两个正整数
输出
一行一个数,t行,表示答案。
思路:
类似于小Z的袜子,考虑直接分块做。
用作初学分块的强化练习。
竟然卡常数,醉。
代码:
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn = 200010;
inline ll get(){
char c = ' '; ll num = 0; int op = 1, ok = 0;
while(1){
c = getchar();
if(c == '-') op = -1;
if(c <= '9' && c >= '0') num = num * 10 + c - '0', ok = 1;
else if(ok) return num * op;
}
}
struct node{
int l, r, id; ll res;
}v[maxn];
int each, n, m, pos[maxn];
ll c[maxn], s[maxn*5], res;
inline bool cmp(node a, node b){return pos[a.l] == pos[b.l] ? a.r < b.r : a.l < b.l;}
inline bool cmp_id(node a, node b){return a.id < b.id;}
inline void update(int p, int k){
res += (ll)(c[p]*s[c[p]]*k*2 + c[p]*k*k);
s[c[p]] += k;
}
int main(){
scanf("%d%d", &n, &m), each = (ll)sqrt(n);
for(int i = 1; i <= n; i ++) c[i] = get();
for(int i = 1; i <= n; i ++) pos[i] = (i-1)/each+1;
for(int i = 1; i <= m; i ++) v[i].l = get(), v[i].r = get(), v[i].id = i;
sort(v+1, v+1+m, cmp);
for(int i = 1, l = 1, r = 0; i <= m; i ++){
for( ; r < v[i].r; r ++) update(r+1, 1);
for( ; r > v[i].r; r --) update(r, -1);
for( ; l < v[i].l; l ++) update(l, -1);
for( ; l > v[i].l; l --) update(l-1, 1);
v[i].res = res;
} sort(v+1, v+1+m, cmp_id);
for(int i = 1; i <= m; i ++) printf("%I64d\n", v[i].res);
return 0;
}