https://vjudge.net/problem/CodeForces-86D
题目大意:
n
n
n个元素的数组,
m
m
m个询问
(
l
,
r
)
(l,r)
(l,r),输出
[
l
,
r
]
[l,r]
[l,r]的价值总和。如果一个数
s
s
s在
[
l
,
r
]
[l,r]
[l,r]内出现了
c
n
t
cnt
cnt次,那么这个数的价值就等于
c
n
t
∗
c
n
t
∗
s
cnt*cnt*s
cnt∗cnt∗s。
思路:莫队板题呀。一看到可以离线,而且从 [ l , r ] [l,r] [l,r]的答案可以很快的计算出相邻区间的答案,直接上莫队搞就行了。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int n,m;
int a[maxn],pos[maxn];
ll res,ans[maxn],cnt[int(1e6+5)];
struct node
{
int l,r,idx;
bool operator <(const node &a)
{
if(pos[l]==pos[a.l])
return r<a.r;
return pos[l]<pos[a.l];
}
}q[maxn];
inline void add(int val)
{
res-=cnt[val]*cnt[val]*val;
++cnt[val];
res+=cnt[val]*cnt[val]*val;
}
inline void sub(int val)
{
res-=cnt[val]*cnt[val]*val;
--cnt[val];
res+=cnt[val]*cnt[val]*val;
}
int main()
{
scanf("%d%d",&n,&m);
int dis=sqrt(n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
pos[i]=(i-1)/dis+1;
}
for(int i=0;i<m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].idx=i;
}
sort(q,q+m);
int l=1,r=0;
for(int i=0;i<m;i++)
{
while(l<q[i].l)
sub(a[l++]);
while(l>q[i].l)
add(a[--l]);
while(r<q[i].r)
add(a[++r]);
while(r>q[i].r)
sub(a[r--]);
ans[q[i].idx]=res;
}
for(int i=0;i<m;i++)
printf("%I64d\n",ans[i]);
return 0;
}