zoukankan      html  css  js  c++  java
  • 【洛谷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)值先减去原本的值的平方,再加上新的值的平方)。
    把式子化简之后就是:

    • 如果(cnt_i)多了一个,那(ans+=2*cnt[x]+1)
    • 如果(cnt_i)少了一个,那(ans-=2*cnt[x]-1)

    然后我们把询问中(frac {l}{sqrt{n}})相同的数分为一组(这里分块的大小是(sqrt{n}),一般来说随机数据的话区(sqrt{n})会比较好,但是不同的题目分块的大小也可以不同)
    然后在同一组内的询问,我们按照询问的(r)值从小到大排序。
    这样排序后暴搜的时间复杂度就变成了(O(nsqrt{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
    ",p[j].ans);
        return 0;
    }
    
  • 相关阅读:
    第四篇博客
    第三篇博客
    第二篇博客
    DS博客作业04--图
    DS博客作业03--树
    DS博客作业02--栈和队列
    C博客作业05--指针
    C博客作业04-数组
    C语言博客作业03--函数
    C语言博客作业02--循环结构
  • 原文地址:https://www.cnblogs.com/linjiale/p/11764942.html
Copyright © 2011-2022 走看看