题目描述
小B有一个序列,包含N个1~K之间的整数。他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数。小B请你帮助他回答询问。
输入输出格式
输入格式:第一行,三个整数N、M、K。
第二行,N个整数,表示小B的序列。
接下来的M行,每行两个整数L、R。
输出格式:M行,每行一个整数,其中第i行的整数表示第i个询问的答案。
输入输出样例
说明
对于全部的数据,1<=N、M、K<=50000
【解题思路】
这题也是一道莫队的模板题
关键在于ADD和REMOVE函数
ns+=2*cnt[a[pos]]-1;
cnt[a[pos]]的平方-cnt[a[pos]-1]的平方
根据完全平方公式可得
其余同理
【code】
1 #include <cstdio> 2 #include <cmath> 3 #include <algorithm> 4 #include <iostream> 5 using namespace std; 6 int a[100005],cnt[100005]; 7 int n,m,k,curL,curR,ans; 8 int block; 9 struct Node{ 10 int l; 11 int r; 12 int id; 13 }q[100005]; 14 int ANS[100005]; 15 inline bool cmp(Node a,Node b){ 16 return (a.l/block)^(b.l/block)?a.l<b.l:(((a.l/block)&1)?a.r<b.r:a.r>b.r); 17 } 18 19 inline void add(int pos){ 20 cnt[a[pos]]++; 21 ans+=2*cnt[a[pos]]-1; 22 } 23 inline void remove(int pos){ 24 cnt[a[pos]]--; 25 ans-=2*cnt[a[pos]]+1; 26 } 27 int main(){ 28 scanf("%d%d%d",&n,&m,&k); 29 for(register int i=1;i<=n;i++) 30 scanf("%d",&a[i]); 31 block=sqrt(n)*1.0; 32 for(register int i=1;i<=m;i++){ 33 scanf("%d%d",&q[i].l,&q[i].r); 34 q[i].id=i; 35 } 36 sort(q+1,q+m+1,cmp); 37 curL=1; 38 curR=0; 39 for(register int i=1;i<=m;i++){ 40 while(curL>q[i].l)add(--curL); 41 while(curR<q[i].r)add(++curR); 42 while(curL<q[i].l)remove(curL++); 43 while(curR>q[i].r)remove(curR--); 44 ANS[q[i].id]=ans; 45 } 46 for(register int i=1;i<=m;i++) 47 printf("%d\n",ANS[i]); 48 return 0; 49 }