题目描述
小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: 复制
6 4 3 1 3 2 1 1 3 1 4 2 6 3 5 5 6
输出样例#1: 复制
6 9 5 2
说明
对于全部的数据,1<=N、M、K<=50000
#include<bits/stdc++.h>
using namespace std;
int n,m,k,col[50003],Be[50003],sum[50003],unit;
long long ans;
struct node
{
int l,r,ID;
long long A;
}q[50003];
bool cmp(node a,node b)
{
if(Be[a.l]==Be[b.l])//在一个块里
return a.r<b.r;//按右边的排序
else
return a.l<b.l;//不然按左边的排序
}
void revise(int x,int add)
{
ans-=sum[col[x]]*sum[col[x]];//消除影响
sum[col[x]]+=add;//更新
ans+=sum[col[x]]*sum[col[x]];//加上影响
}
bool CMP(node a,node b)
{
return a.ID<b.ID;//按ID排序 准备输出
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
unit=sqrt(n);
for(int i=1;i<=n;i++)
{
scanf("%d",&col[i]);
Be[i]=i/unit+1;//分块
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].ID=i;
}
sort(q+1,q+m+1,cmp);
int l=1,r=0;
for(int i=1;i<=m;i++)
{
while(l<q[i].l) revise(l,-1),l++;//一开始l在左边 减少的就是这个值
while(l>q[i].l) revise(l-1,1),l--;//l一开始在右边 增加的是右边一个(移过去的那个)
while(r<q[i].r) revise(r+1,1),r++;//r一开始在左边 增加的是右边一个(移过去的那个)
while(r>q[i].r) revise(r,-1),r--;//r一开始在右边 减少的就是r这个值
q[i].A=ans;//答案的值就是ans
}
sort(q+1,q+m+1,CMP);
for(int i=1;i<=m;i++)
printf("%lld\n",q[i].A);
return 0;
}