P2709 小B的询问 (莫队板子)
题目描述
小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
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int N=500005; int n,m,k; int a[N],c[N]; int ans,Ans[N]; int belong[N]; struct Querry { int tim,l,r; bool operator < (const Querry &a) const { if(belong[l]==belong[a.l]) return belong[r]<belong[a.r]; return belong[l]<belong[a.l]; } }q[N]; int read() { char c=getchar();int num=0; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num; } void init() { n=read(),m=read(),k=read(); int size=sqrt(n); for(int i=1;i<=n;++i) a[i]=read(), belong[i]=(i-1)/size+1; for(int i=1;i<=m;++i) q[i].l=read(),q[i].r=read(),q[i].tim=i; sort(q+1,q+m+1); } /*void update(int now,bool type) { if(type) { ans-=c[now]*c[now]; ++c[now]; ans+=c[now]*c[now]; } else { ans-=c[now]*c[now]; --c[now]; ans+=c[now]*c[now]; } }*/ void update(int now,bool type) { if(type) ans+=c[now]<<1|1,++c[now]; //(a+1)*(a+1)==a*a+2*a+1,比a*a多了2*a+1 else ans-=(c[now]<<1)-1,--c[now]; //(a-1)*(a-1)==a*a-2*a+1,比a*a少了2*a-1 } void work() { for(int i=q[1].l;i<=q[1].r;++i) update(a[i],1); Ans[q[1].tim]=ans; for(int i=2;i<=m;++i) { if(q[i].l>q[i-1].l) for(int j=q[i-1].l;j<q[i].l;++j) update(a[j],0); if(q[i].l<q[i-1].l) for(int j=q[i].l;j<q[i-1].l;++j) update(a[j],1); if(q[i].r<q[i-1].r) for(int j=q[i].r+1;j<=q[i-1].r;++j) update(a[j],0); if(q[i].r>q[i-1].r) for(int j=q[i-1].r+1;j<=q[i].r;++j) update(a[j],1); Ans[q[i].tim]=ans; } for(int i=1;i<=m;++i) printf("%d\n",Ans[i]); } int main() { init(); work(); return 0; }