题意大致是这样的:
给你一个数列a。
只有查询操作,每次查询一个区间。 求出:
其中c[i]表示数字i在区间[l,r]中出现的次数。
容易发现,当c[i]=0的时候我们无需进行累加操作。
使用莫队解决,该莫队中的L和R移动的时候,分两种情况。
1.L增加或者R减少(即区间缩小)对应移动到的数字为x,那么维护的now此时:
要减去值为:x的出现次数 * x的出现次数 - (x的出现次数 -1)*(x的出现次数 -1)
2.L减少或者R增加(即区间扩大)对应移动到的数字为x,那么维护的now此时:
要增加值为:(x的出现次数+1)*(x的出现次数+1)- x的出现次数 * x的出现次数
AC代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e6+10;
struct query{
int l,r,b,id;
}e[N];
int n,m,k,a[N],cnt[N],ans[N];
bool cmp(query a,query b){
return (a.b^b.b) ? a.b<b.b : (a.b&1 ? a.r<b.r : a.r>b.r);
}
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0' || ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
void write(int x){if(x<0) putchar('-'),x=-x;if(x>9) write(x/10);putchar(x%10+'0');return;}
signed main(){
n=read(),m=read(),k=read();
int len=sqrt(n);
for(int i=1;i<=n;i++){
a[i]=read();
}
for(int i=1;i<=m;i++) {
e[i].l=read(),e[i].r=read();
e[i].id=i;
e[i].b=e[i].l/len;
}
sort(e+1,e+1+m,cmp);
int l=1,r=0,now=0;
for(int i=1;i<=m;i++){
int ql=e[i].l,qr=e[i].r;
while(l<ql){
if(cnt[a[l]])now-=cnt[a[l]]*cnt[a[l]]-(cnt[a[l]]-1)*(cnt[a[l]]-1);
--cnt[a[l++]];
}
while(l>ql){
cnt[a[--l]]++;
if(cnt[a[l]])now+=cnt[a[l]]*cnt[a[l]]-(cnt[a[l]]-1)*(cnt[a[l]]-1);
}
while(r<qr){
cnt[a[++r]]++;
if(cnt[a[r]])now+=cnt[a[r]]*cnt[a[r]]-(cnt[a[r]]-1)*(cnt[a[r]]-1);
}
while(r>qr){
if(cnt[a[r]])now-=cnt[a[r]]*cnt[a[r]]-(cnt[a[r]]-1)*(cnt[a[r]]-1);
--cnt[a[r--]];
}
ans[e[i].id]=now;
}
for(int i=1;i<=m;i++){
write(ans[i]);puts("");
}
return 0;
}