题目
https://www.luogu.org/problemnew/show/P2709
思路
莫队经典例题
这题询问每一种数字数量的平方和,那么我们在左移或右移的时候记录一下就好了,当每一种数字的种类数加1或减1的时候,我们需要减去以前这个数对答案的影响,加上现在对答案的影响。
假设原来数字a的种类数为k,如今又加入一个a,那么先ans-=k2,然后ans+=(k+1)2.,删除同理。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=5e4+77;
int b[maxn],t[maxn],n,m,k,len;;
long long ans[maxn],s;
struct node
{
int l,r,id,d;
}a[maxn];
bool cmp(node a,node b)
{
return a.id<b.id||a.id==b.id&&a.r<b.r;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
len=sqrt(n);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a[i].l,&a[i].r);
a[i].id=(a[i].l+len-1)/len;
a[i].d=i;
}
sort(a+1,a+m+1,cmp);
int l=a[1].l;
int r=a[1].l-1;
for(int i=1;i<=m;i++)
{
while(l<a[i].l) s-=2*--t[b[l++]]+1;
while(l>a[i].l) s+=2*++t[b[--l]]-1;
while(r>a[i].r) s-=2*--t[b[r--]]+1;
while(r<a[i].r) s+=2*++t[b[++r]]-1;
ans[a[i].d]=s;
}
for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
return 0;
}