其他分享
首页 > 其他分享> > 【洛谷P2709】小B的询问

【洛谷P2709】小B的询问

作者:互联网

小B的询问

题目描述

小B有一个序列,包含\(N\)个\(1~K\)之间的整数。他一共有\(M\)个询问,每个询问给定一个区间\([L..R]\),求\(\sum^{K}_{i=1}{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 \le N\)、\(M\)、\(K \le 50000\)

题解

一道莫队板题(说不定也可以用其他方法做,但是我太菜了,只会莫队)。
我们用\(cnt[j]\)和\(l,r\)维护\(l\)到\(r\)区间内\(j\)这个数字的个数,并且维护一个\(ans\)值,然后我们移动\(l\)和\(r\)的时候快速地维护这个数组和\(ans\)值(\(ans\)值先减去原本的值的平方,再加上新的值的平方)。
然后我们把询问中\(\frac {l}{\sqrt{n}}\)相同的数分为一组(这里分块的大小是\(\sqrt{n}\),一般来说随机数据的话区\(\sqrt{n}\)会比较好,但是不同的题目分块的大小也可以不同)
然后在同一组内的询问,我们按照询问的\(r\)值从小到大排序。
这样排序后暴搜的时间复杂度就变成了\(O(n\sqrt{n})\)了,能过此题。
上代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,k;
int a[1000009];
struct aa{
    int l,r,x,ans;
}p[1000009];
int sq;
bool cmp(aa x,aa y){
    if(x.l/sq<y.l/sq) return 1;
    if(x.l/sq>y.l/sq) return 0;
    return x.r<y.r;
}
int cnt[1000009];
bool cmpp(aa x,aa y){return x.x<y.x;}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    sq=sqrt(n);
    for(int j=1;j<=n;j++)
        scanf("%d",&a[j]);
    for(int j=1;j<=m;j++){
        scanf("%d%d",&p[j].l,&p[j].r);
        p[j].x=j;
    }
    sort(p+1,p+m+1,cmp);
    int ll=1,rr=1,ss=1;
    cnt[a[1]]=1;
    for(int j=1;j<=m;j++){
        while(rr<p[j].r){
            rr++;
            ss-=cnt[a[rr]]*cnt[a[rr]];
            cnt[a[rr]]++;
            ss+=cnt[a[rr]]*cnt[a[rr]];
        }
        while(ll>p[j].l){
            ll--;
            ss-=cnt[a[ll]]*cnt[a[ll]];
            cnt[a[ll]]++;
            ss+=cnt[a[ll]]*cnt[a[ll]];
        }
        while(rr>p[j].r){
            ss-=cnt[a[rr]]*cnt[a[rr]];
            cnt[a[rr]]--;
            ss+=cnt[a[rr]]*cnt[a[rr]];
            rr--;
        }
        while(ll<p[j].l){
            ss-=cnt[a[ll]]*cnt[a[ll]];
            cnt[a[ll]]--;
            ss+=cnt[a[ll]]*cnt[a[ll]];
            ll++;
        }
        p[j].ans=ss;
    }
    sort(p+1,p+m+1,cmpp);
    for(int j=1;j<=m;j++)
        printf("%d\n",p[j].ans);
    return 0;
}

标签:cnt,洛谷,rr,ss,询问,int,P2709,ll
来源: https://www.cnblogs.com/linjiale/p/11764942.html