题目
一共有M个询问,每个询问给定一个区间[L..R][L..R][L..R],求Σ(c(i)2)\Sigma(c(i)^2)Σ(c(i)2)的值,其中c(i)c(i)c(i)表示数字iii在[L..R][L..R][L..R]中的重复次数。
分析
然而,这道题看起来是暴力,实际上,还是暴力,只是用一种特殊的方式暴力,就是莫队,莫队是用一种O(1)O(1)O(1)的方式移动一个区间,然而这样看起来像O(n2)O(n^2)O(n2),所以再找一种好的办法,排序!当然除此之外,每个区间不超过n\sqrt nn,那么这种分块的东西,时间复杂度O(nn)O(n\sqrt n)O(nn)
代码
#include <cstdio>
#include <cmath>
#include <algorithm>
struct rec{int l,r,rk;}a[50001];
int n,m,b[50001],ans[50001],cnt[50001],t;
int in(){
int ans=0; char c=getchar();
while (c<48||c>57) c=getchar();
while (c>47&&c<58) ans=ans*10+c-48,c=getchar();
return ans;
}
bool cmp(const rec &x,const rec &y){
if ((x.l-1)/t!=(y.l-1)/t) return (x.l-1)/t<(y.l-1)/t;
else return x.r<y.r;
}
void print(int ans){if (ans>9) print(ans/10); putchar(ans%10+48);}
int main(){
n=in(); m=in(); in(); t=sqrt(n);
for (int i=1;i<=n;i++) b[i]=in();
for (int i=1;i<=m;i++)
a[i].l=in(),a[i].r=in(),a[i].rk=i;
std::stable_sort(a+1,a+1+m,cmp);//按照区间排序
int l=1,r=0,Ans=0;
for (int i=1;i<=m;i++){
while (l>a[i].l) l--,cnt[b[l]]++,Ans+=cnt[b[l]]-1<<1|1;//往左边移
while (r<a[i].r) r++,cnt[b[r]]++,Ans+=cnt[b[r]]-1<<1|1;//往右边移
while (l<a[i].l) cnt[b[l]]--,Ans-=cnt[b[l]]<<1|1,l++;//往回移
while (r>a[i].r) cnt[b[r]]--,Ans-=cnt[b[r]]<<1|1,r--;//往回移
ans[a[i].rk]=Ans;
}
for (int i=1;i<=m;i++) print(ans[i]),putchar('\n');
return 0;
}