莫队裸题,不讲
主要是我们如何得到结果
我们发现假如在上一个区间内a出现了b次,那么那么显然在这个区间内的初始ans=b^2,然后假如我们又找到了一个a,那么ans=(b+1)^2=b^2+2b+1,所以我们就可以转移了,但是因为我们是先找到的次数,所以,我们+2*b的时候实际上加的是2*(b+1)+1,也就是说我们还需要-1,所以转移变成了ans+=(2*cnt[b]-1)
代码
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inl inline
#define lli long long int
using namespace std;
const int M=50005;
struct que{int l,r,id;lli ans;}e[M];
int n,m,q,block;
int b[M],bloc[M];
lli cnt[M],em[M];
inl int read()
{
int x=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inl bool cmp1(que a,que b)
{
if (bloc[a.l]==bloc[b.l]) return a.r<b.r;
return a.l<b.l;
}
inl bool cmp2(que a,que b){return a.id<b.id;}
inl void slove()
{
int l=1,r=0;lli ans=0;
for (int i=1;i<=m;i++)
{
for (;l>e[i].l;) cnt[b[--l]]++,ans+=(2*cnt[b[l]]-1);
for (;r<e[i].r;) cnt[b[++r]]++,ans+=(2*cnt[b[r]]-1);
for (;l<e[i].l;l++) cnt[b[l]]--,ans-=(2*cnt[b[l]]+1);
for (;r>e[i].r;r--) cnt[b[r]]--,ans-=(2*cnt[b[r]]+1);
e[i].ans=ans;
}
return ;
}
int main()
{
n=read();m=read();q=read();block=sqrt(n);
for (int i=1;i<=n;i++) b[i]=read();
for (int i=1;i<=n;i++)
bloc[i]=(i-1)/block+1;
for (int i=1;i<=m;i++)
e[i].l=read(),e[i].r=read(),e[i].id=i;
sort(e+1,e+m+1,cmp1);
slove();
sort(e+1,e+m+1,cmp2);
for (int i=1;i<=m;i++)
printf("%lld\n",e[i].ans);
return 0;
}