题意:
给定一个长度为n的序列,序列里的数≤k,m个询问l,r:求sigma(i,1,k)c[i]^2,c[i]为i在[l,r]的出现次数。n,m,k≤50000。
题解:
莫队算法直接上。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <cmath> 5 #define inc(i,j,k) for(int i=j;i<=k;i++) 6 #define maxn 50010 7 #define ll long long 8 using namespace std; 9 10 inline int read(){ 11 char ch=getchar(); int f=1,x=0; 12 while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} 13 while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); 14 return f*x; 15 } 16 struct ask{int l,r,id;}asks[maxn]; int bel[maxn],n,sz,m,k,l,r; ll ans,a[maxn],c[maxn],p[maxn]; 17 bool cmp(ask a,ask b){return bel[a.l]==bel[b.l]?a.r<b.r:bel[a.l]<bel[b.l];} 18 ll sqr(ll a){return a*a;} 19 int main(){ 20 n=read(); m=read(); k=read(); inc(i,1,n)a[i]=read(); sz=(int)sqrt(n); 21 inc(i,1,n)bel[i]=(i-1)/sz+1; inc(i,1,m)asks[i]=(ask){read(),read(),i}; 22 sort(asks+1,asks+m+1,cmp); ans=0; l=1; r=0; 23 inc(i,1,m){ 24 while(asks[i].r>r)r++,ans-=sqr(c[a[r]]),c[a[r]]++,ans+=sqr(c[a[r]]); 25 while(asks[i].l<l)l--,ans-=sqr(c[a[l]]),c[a[l]]++,ans+=sqr(c[a[l]]); 26 while(asks[i].r<r)ans-=sqr(c[a[r]]),c[a[r]]--,ans+=sqr(c[a[r]]),r--; 27 while(asks[i].l>l)ans-=sqr(c[a[l]]),c[a[l]]--,ans+=sqr(c[a[l]]),l++; 28 p[asks[i].id]=ans; 29 } 30 inc(i,1,m)printf("%lld ",p[i]); return 0; 31 }
20160906