3781: 小B的询问
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 196 Solved: 135
[ Submit][ Status]
Description
小B有一个序列,包含N个1~K之间的整数。他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数。小B请你帮助他回答询问。
Input
第一行,三个整数N、M、K。
第二行,N个整数,表示小B的序列。
接下来的M行,每行两个整数L、R。
Output
M行,每行一个整数,其中第i行的整数表示第i个询问的答案。
Sample Input
6 4 3
1 3 2 1 1 3
1 4
2 6
3 5
5 6
1 3 2 1 1 3
1 4
2 6
3 5
5 6
Sample Output
6
9
5
2
9
5
2
网上题解都说是莫队算法,但是当时脑子一抽写了个分块,然后就过了。。。
询问离线,按照r值排序,对于出现个数大于sqrt(n)的直接暴力二分即可,而个数小于sqrt(n)的部分可以这样处理,由于1,4,9,16是数列1,3,5,7的前缀和,对于一个数字在pos出现,即在pos处+1,如果之前出现过,则在之前出现的位置都+2,统计区间和[l,r]即为当前询问答案,具体详见代码。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<cmath> using namespace std; #define MAXN 50010 #define MAXB 300 typedef long long qword; inline qword sqr(int x) { return (qword)x*x; } int a[MAXN]; int rcv[MAXN]; int prv[MAXN]; int tot[MAXN]; int vec[MAXB][MAXN]; int vpos[MAXN],topv=0; struct qur_t { int id,x,y; qword ans; }qur[MAXN]; bool cmp_y(qur_t q1,qur_t q2) { return q1.y<q2.y; } bool cmp_id(qur_t q1,qur_t q2) { return q1.id<q2.id; } int tarr[MAXN]; void Add_tarr(int pos,int v) { while (pos<MAXN) { tarr[pos]+=v; pos+=pos&(-pos); } } int Query_tarr(int pos) { int ret=0; while (pos) { ret+=tarr[pos]; pos-=pos&(-pos); } return ret; } int main() { // freopen("input.txt","r",stdin); // freopen("ouput.txt","w",stdout); int x,y,z,n,m,t; scanf("%d%d%d",&n,&m,&t); for (int i=1;i<=n;i++) scanf("%d",a+i); for (int i=1;i<=n;i++) { prv[i]=rcv[a[i]]; rcv[a[i]]=i; } for (int i=1;i<=n;i++) tot[a[i]]++; int bs=(int)sqrt(max(n,t))*2; for (int i=1;i<=t;i++) if (tot[i]>=bs) vpos[i]=++topv; for (int i=1;i<=n;i++) if (vpos[a[i]]) vec[vpos[a[i]]][++vec[vpos[a[i]]][0]]=i; for (int i=1;i<=m;i++) scanf("%d%d",&qur[i].x,&qur[i].y),qur[i].id=i; sort(qur+1,qur+m+1,cmp_y); int *it1,*it2; for (int i=1;i<=m;i++) { for (int j=1;j<=topv;j++) { it1=lower_bound(&vec[j][1],&vec[j][vec[j][0]] + 1,qur[i].x); it2=upper_bound(it1,&vec[j][vec[j][0]] + 1,qur[i].y); it2--; qur[i].ans+=sqr((int)(it2-it1+1)); } } int qnow=1; for (int i=1;i<=n;i++) { if (!vpos[a[i]]) { Add_tarr(i,1); x=prv[i]; while (x) { Add_tarr(x,2); x=prv[x]; } } while (qnow<=m && qur[qnow].y==i) { qur[qnow].ans+=Query_tarr(i)-Query_tarr(qur[qnow].x-1); qnow++; } } sort(qur+1,qur+m+1,cmp_id); for (int i=1;i<=m;i++) { printf("%lld\n",qur[i].ans); } }