题目大意:
题目链接:https://ac.nowcoder.com/acm/contest/1085/G
小sun最近突然对区间来了兴趣,现在他有这样一个问题想问问你:
给你n个数,每个数为 ,现在有个询问,每个询问,需要求出:
其中代表在这个区间中出现的次数。
你能帮帮他吗?
思路:
对于区间的每一个数字,一共有个,每一个的贡献是。所以数字的贡献是。
题目中保证了,而且没有强制在线,明显就是一道莫队的板子题了。
而且这道题和小Z的袜子还很像,改一下就可以了。
代码:
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=100010;
int n,m,T,l,r,a[N],pos[N];
ll ans[N],sum,s[N];
struct Ask
{
int l,r,id;
}ask[N];
bool cmp(Ask x,Ask y)
{
if (pos[x.l]<pos[y.l]) return 1;
if (pos[x.l]>pos[y.l]) return 0;
return x.r<y.r;
}
void add(int x)
{
sum-=s[a[x]]*s[a[x]]*a[x];
s[a[x]]++;
sum+=s[a[x]]*s[a[x]]*a[x];
}
void dev(int x)
{
sum-=s[a[x]]*s[a[x]]*a[x];
s[a[x]]--;
sum+=s[a[x]]*s[a[x]]*a[x];
}
int main()
{
scanf("%d%d",&n,&m);
T=(int)sqrt(m);
if (m%T) T++;
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
for (int i=1;i<=m;i++)
{
scanf("%d%d",&ask[i].l,&ask[i].r);
ask[i].id=i;
pos[i]=(i-1)/T+1;
}
sort(ask+1,ask+1+m,cmp);
l=1;
for (int i=1;i<=m;i++)
{
for (;l<ask[i].l;l++) dev(l);
for (;l>ask[i].l;l--) add(l-1);
for (;r<ask[i].r;r++) add(r+1);
for (;r>ask[i].r;r--) dev(r);
ans[ask[i].id]=sum;
}
for (int i=1;i<=m;i++)
printf("%lld
",ans[i]);
return 0;
}