• 【分块】二


    于是分块就来到了第二题。

    首先还是感谢hzw学长。

    以下是题面(感谢zcr xyf xzp小组)

    小M的简单题(easy.pas/.cpp/.c)

    时间限制:3s 内存限制:128MB

    题目描述:

    小M是某知名高中的学生,有一天,他请他的n个同学吃苹果,同学们排成一行,且手中已经有一些苹果。为了表示他的大方,有时他会给l到r的同学x个苹果,但为了了解分配的情况,有时他会询问l到r的同学中拥有的苹果数小于x的人的个数。现在,小M想让你帮他解决这道简单题。

    输入格式:

    第一行:两个整数n,m表示n个同学,m组询问。

    第二行:n个数,a[1],a[2]...a[n],a[i]表示第i个同学一开始手中的苹果数。(0<=a[i]<=3e4)

    第3~m+2行:每行表示一组询问,格式为C l r x表示给l到r的同学x个苹果,或者Q l r x表示询问l到r的同学中拥有的苹果数小于x的人的个数。(1<=l<=r<=n,0<=x<=3e4)

    输出格式:

    每行一个数,输出l到r的同学中拥有的苹果数小于x的人的个数。

    样例输入1:

    5 5

    1 6 3 2 3

    Q 1 3 3

    C 1 2 2

    Q 3 4 3

    C 2 3 1

    Q 2 3 4

    样例输出1:

    1

    1

    0

    样例输入2:

    5 4

    2 3 1 3 4

    C 4 5 3

    C 1 5 1

    C 2 3 2

    Q 1 3 4

    样例输出2:

    1

    数据范围:

     

    N

    M

    特殊说明

    第1~3组

    1000

    1000

    /

    第4组

    30000

    1000

    r-l<=1000

    第5组

    30000

    1000

    询问均在修改后

    第6组

    30000

    30000

    每次的x相同

    第7~10组

    30000

    30000

    /

    【简述】

    给出一个长为n的数列,以及n个操作,操作涉及区间加法,询问区间内小于某个值x的元素个数。

    【题解】

    有了上一题的经验,我们可以发现,数列简单分块问题实际上有三项东西要我们思考:

    对于每次区间操作:

    1.不完整的块 的O(√n)个元素怎么处理?

    2.O(√n)个 整块 怎么处理?

    3.要预处理什么信息(复杂度不能超过后面的操作)?

    我们先来思考只有询问操作的情况,不完整的块枚举统计即可;而要在每个整块内寻找小于一个值的元素数,于是我们不得不要求块内元素是有序的,这样就能使用二分法对块内查询,需要预处理时每块做一遍排序,复杂度O(nlogn),每次查询在√n个块内二分,以及暴力2√n个元素,总复杂度O(nlogn + n√nlog√n)。

    可以通过均值不等式计算出更优的分块大小,就不展开讨论了

    那么区间加怎么办呢?

    套用第一题的方法,维护一个加法标记,略有区别的地方在于,不完整的块修改后可能会使得该块内数字乱序,所以头尾两个不完整块需要重新排序,复杂度分析略。

    在加法标记下的询问操作,块外还是暴力,查询小于(x – 加法标记)的元素个数,块内用(x – 加法标记)作为二分的值即可。

    标程:

     1 #include<cmath>
     2 #include<vector>
     3 #include<cstdio>
     4 #include<algorithm>
     5 using namespace std;
     6 vector<long long>v[1005];
     7 int blo,n,m,l,r,x,bl[100005];
     8 long long a[100005],tag[100005];
     9 char op[105];
    10 void reset(int x)
    11 {
    12     v[x].clear();
    13     for (int i=(x-1)*blo+1; i<=min(x*blo,n); i++)
    14         v[x].push_back(a[i]);
    15     sort(v[x].begin(),v[x].end());
    16 }
    17 void add(int l,int r,int x)
    18 {
    19     for (int i=l; i<=min(bl[l]*blo,r); i++)
    20         a[i]+=x;
    21     reset(bl[l]);
    22     if (bl[l]!=bl[r])
    23     {
    24         for (int i=(bl[r]-1)*blo+1; i<=r; i++)
    25             a[i]+=x;
    26         reset(bl[r]);
    27     }
    28     for (int i=bl[l]+1; i<=bl[r]-1; i++)
    29         tag[i]+=x;
    30 }
    31 int query(int l,int r,int x)
    32 {
    33     int ans=0;
    34     for (int i=l; i<=min(bl[l]*blo,r); i++)
    35         if (a[i]+tag[bl[l]]<x) ans++;
    36     if (bl[l]!=bl[r])
    37     {
    38         for (int i=(bl[r]-1)*blo+1; i<=r; i++)
    39             if (a[i]+tag[bl[r]]<x) ans++;
    40     }
    41     for (int i=bl[l]+1; i<=bl[r]-1; i++)
    42     {
    43         int c=x-tag[i];
    44         ans+=lower_bound(v[i].begin(),v[i].end(),c)-v[i].begin();
    45     }
    46     return ans;
    47 }
    48 int main()
    49 {
    50     scanf("%d%d",&n,&m);
    51     blo=sqrt(n);
    52     for (int i=1; i<=n; i++)
    53     {
    54         scanf("%lld",&a[i]);
    55         bl[i]=(i-1)/blo+1;
    56         v[bl[i]].push_back(a[i]);
    57     }
    58     for (int i=1; i<=bl[n]; i++)
    59         sort(v[i].begin(),v[i].end());
    60     for (int i=1; i<=m; i++)
    61     {
    62         scanf("%s",op);
    63         scanf("%d%d%d",&l,&r,&x);
    64         if (op[0]=='C') add(l,r,x);
    65         else printf("%d
    ",query(l,r,x));
    66     }
    67     return 0;
    68 }

    (以上程序感谢xzp同学嘤嘤嘤)

  • 相关阅读:
    php AppStore内购付款验证
    NodeJS
    Electron 的中文乱码问题
    Flexbox 弹性盒子布局的使用
    springboot整合quartz
    第4章:逆向分析技术--64位软件逆向技术
    第51章:静态反调试技术——API查询
    第51章:静态反调试技术
    第48章:SEH
    第47章:PEB
  • 原文地址:https://www.cnblogs.com/Hathawaxy/p/6894858.html
Copyright © 2020-2023  润新知