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个询问的答案。
输入输出样例
输入
6 4 3 1 3 2 1 1 3 1 4 2 6 3 5 5 6
输出
6 9 5 2
说明/提示
对于全部的数据,1<=N、M、K<=50000
普通莫队
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e4+6;
int a[maxn];
int b[maxn];
int ans[maxn];
int sum=0;
struct node{
int l,r;
int id;
int sum;
}sz[maxn];
bool cmp(node x,node y)//如果在同一块按r排序,否则按l排序
{
if(b[x.l]!=b[y.l])
return x.l<y.l;
else
return x.r<y.r;
}
bool CMP(node x,node y)
{
return x.id<y.id;
}
void revise(int v,int pos)//消除或增加影响
{
sum=sum-(ans[a[v]]*ans[a[v]]);
ans[a[v]]+=pos;
sum=sum+(ans[a[v]]*ans[a[v]]);
}
int main()
{
int n,m,k;
scanf("%d %d %d",&n,&m,&k);
int block=pow(n,0.666666);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=i/block+1;
}
for(int i=0;i<m;i++)
{
scanf("%d %d",&sz[i].l,&sz[i].r);
sz[i].id=i;
}
sort(sz,sz+m,cmp);
int l=1,r=0;
for(int i=0;i<m;i++)
{//区间在L-R内,L右移影响减小,左移动 影响变大,R左移影响减小,右移增大
while(sz[i].l>l) revise(l,-1),l++;//如果l小于要查询的位置,l就要右移,把当前地方影响消去
while(sz[i].l<l) revise(l-1,1),l--;//如果l大于要查询的位置,l左移,把移动位置影响加上
while(sz[i].r>r) revise(r+1,1),r++;
while(sz[i].r<r) revise(r,-1),r--;
sz[i].sum=sum;
}
sort(sz,sz+m,CMP);
for(int i=0;i<m;i++)
{
printf("%d\n",sz[i].sum);
}
}