BZOJ3781:小B的询问(莫队)
Description
小B有一个序列,包含N个1~K之间的整数。他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数。小B请你帮助他回答询问。
Input
第一行,三个整数N、M、K。
第二行,N个整数,表示小B的序列。
接下来的M行,每行两个整数L、R。
Output
M行,每行一个整数,其中第i行的整数表示第i个询问的答案。
Sample Input
6 4 3
1 3 2 1 1 3
1 4
2 6
3 5
5 6
1 3 2 1 1 3
1 4
2 6
3 5
5 6
Sample Output
6
9
5
2
9
5
2
HINT
对于全部的数据,1<=N、M、K<=50000
Solution
莫队水题
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cmath> 6 #define N (50000+100) 7 using namespace std; 8 struct node 9 { 10 int l,r,id,ans,ord; 11 }Ask[N]; 12 int a[N],n,m,k,cnt[N],Sigma,l=1,r=0; 13 bool cmp1 (node a,node b){return a.id==b.id?a.r<b.r:a.id<b.id;} 14 bool cmp2 (node a,node b){return a.ord<b.ord;} 15 16 void Ins(int x) 17 { 18 Sigma-=cnt[x]*cnt[x]; 19 cnt[x]++; 20 Sigma+=cnt[x]*cnt[x]; 21 } 22 void Del(int x) 23 { 24 Sigma-=cnt[x]*cnt[x]; 25 cnt[x]--; 26 Sigma+=cnt[x]*cnt[x]; 27 } 28 void MoQueue(int x) 29 { 30 int L=Ask[x].l,R=Ask[x].r; 31 while (l<L) Del(a[l++]); 32 while (l>L) Ins(a[--l]); 33 while (r<R) Ins(a[++r]); 34 while (r>R) Del(a[r--]); 35 Ask[x].ans=Sigma; 36 } 37 int main() 38 { 39 scanf("%d%d%d",&n,&m,&k); 40 int len=pow(n,2.0/3.0); 41 for (int i=1;i<=n;++i) 42 scanf("%d",&a[i]); 43 for (int i=1;i<=m;++i) 44 { 45 scanf("%d%d",&Ask[i].l,&Ask[i].r); 46 Ask[i].id=Ask[i].l/len; 47 Ask[i].ord=i; 48 } 49 sort(Ask+1,Ask+m+1,cmp1); 50 for (int i=1;i<=m;++i) 51 MoQueue(i); 52 sort(Ask+1,Ask+m+1,cmp2); 53 for (int i=1;i<=m;++i) 54 printf("%d\n",Ask[i].ans); 55 }