题目描述
小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;
#define LL long long
#define clr(a) memset(a,0,sizeof(a))
const int MAXN = 1e5+10;
const int INF = 0x3f3f3f3f;
const int N = 50001;
int n,m,k;
int ll,rr;
int tong[N];//记录a[i]出现的次数
int an[N];
int a[N];//原顺序数组
LL kind;
struct node{
int l,r,num;
int id;//分块后块的编号
}q[N];
void del(int p){//del表示删除,ins加入,kind表示当前答案
kind -= 2 * (--tong[a[p]]) + 1;
}
void ins(int p){
kind += 2 * (++tong[a[p]]) - 1;
}
bool cmp(node a,node b){
if(a.id == b.id) return a.r < b.r;//块号相同则按照右界从小到大排序
else return a.id < b.id ;//块号不同则按照块号从小到大排序
}
int main(){
scanf("%d%d%d",&n,&m,&k);
int len = sqrt(n);//分块莫队
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=m;i++){
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id = q[i].l / len;//记录块号
q[i].num = i;
}
sort(q+1,q+m+1,cmp);//排序预处理
ll = q[1].l;
rr = q[1].l - 1;//开始没有点
for(int i=1;i<=m;i++){
while(ll<q[i].l)del(ll++);
while(ll>q[i].l)ins(--ll);
while(rr>q[i].r)del(rr--);
while(rr<q[i].r)ins(++rr);//增加点/减少点
an[q[i].num] = kind;//记录答案
}
for(int i=1;i<=m;i++)
cout<<an[i]<<endl;
}