zoukankan      html  css  js  c++  java
  • bzoj3343 教主的魔法【分块入门】By cellur925

    题意:维护一个数列,给出维护区间加法,询问区间内大于等于某个值的元素个数。

    算法:分块。因为本题第二问显然可以用二分的思想,但是这貌似并不符合区间可加性,线段树好像就不好用了呢。所以本蒟蒻学习了分块。

    这大概是本蒟蒻的第一题正式分块,思想是在hzwer学长的分块入门学的==。

    什么是分块?我们维护数列(貌似树上也可以)信息时可以先采用分治的思想,把数列分成若干连续的块,维护信息可以统一在块上进行维护。假如有一个n元素的数列,根据均值不等式的数学知识(并不会证明),我们把每个块的大小设为根号n可以达到最右效果。但是显然有时根号n并不是整数==,没有关系,我们的数列上大部分都在整块上,只有小部分被遗弃的元素在不完整的块中。

    我们进行区间操作时,把在整块中的元素进行整体操作,那些在不完整的块中的元素进行暴力操作

    总结来说,就是“大块维护,小段朴素”,这也是分块最基本的思想。

    分块的复杂度(根号算法)虽然较其他数据结构可能略高了一些,却是打暴力的好方法,思维较简单,处理问题的范围更广,码量...可能略大(?)

    回到本题的两个操作:

    区间加法:对于一段区间,如果存在被整块覆盖的情况,直接在整块的加法标记上记录,不需在原序列上改动,查询时在加上加法标记;而在不完整的块中的元素,直接暴力修改。

    查询大于等于X的元素个数:想一想如果数列是无序的,我们分的块就完全没用了。但是如果我们在预处理时以及修改时对每个整块进行排序,查询时调用lower_bound/手写二分查找,问题就能轻松得到解决。那些在不完整块中的元素,同理,暴力枚举统计。

    综上,我们不难发现,使用分块算法需要或者只需要想的两个关键:

      怎么维护整块?怎么维护不完整的块?

    分块的更多代码实现细节:

      (几乎每到分块题都要的)bl[i]记录i在第几个块

      bl[i]*blo(blo=sqrt(n))可以得出当前位置(块的右边界),在此基础上变形

      右边界:取min,bl[l]*blo,n(防止越界)

    Code

     1 // luogu-judger-enable-o2
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cmath>
     5 #include<vector>
     6 
     7 using namespace std;
     8 
     9 int n,Q,blo;
    10 int val[1000090],bl[1000090],addtag[1000090];
    11 char opt[5];
    12 vector<int>cnt[5000];
    13 
    14 void update(int x)
    15 {
    16     cnt[x].clear();
    17     for(int i=(x-1)*blo+1;i<=min(x*blo,n);i++)
    18         cnt[x].push_back(val[i]);
    19     sort(cnt[x].begin(),cnt[x].end());
    20 }
    21 
    22 void add(int l,int r,int p)
    23 {
    24     if(l==r) val[l]+=p;
    25     else
    26     {
    27         for(int i=l;i<=min(bl[l]*blo,r);i++)
    28         val[i]+=p;
    29         update(bl[l]);    
    30         if(bl[l]!=bl[r])
    31         {
    32             for(int i=(bl[r]-1)*blo+1;i<=r;i++)
    33                 val[i]+=p;
    34             update(bl[r]);
    35         }
    36         for(int i=bl[l]+1;i<=bl[r]-1;i++)
    37             addtag[i]+=p;
    38     }
    39 }
    40 
    41 int query(int l,int r,int p)
    42 {
    43     int ans=0;
    44     for(int i=l;i<=min(bl[l]*blo,r);i++)
    45         if(val[i]+addtag[bl[l]]>=p) ans++;
    46     if(bl[l]!=bl[r])
    47     {
    48         for(int i=(bl[r]-1)*blo+1;i<=r;i++)
    49             if(val[i]+addtag[bl[r]]>=p) ans++;
    50     }
    51     for(int i=bl[l]+1;i<=bl[r]-1;i++)
    52     {
    53         int tmp=p-addtag[i];
    54         int pos=lower_bound(cnt[i].begin(),cnt[i].end(),tmp)-cnt[i].begin();
    55            ans+=blo-pos;
    56 //          ans+=find(i,tmp);
    57     }
    58     return ans;
    59 }
    60 
    61 int main()
    62 {
    63     scanf("%d%d",&n,&Q);
    64     for(int i=1;i<=n;i++) scanf("%d",&val[i]);
    65     blo=sqrt(n);
    66     for(int i=1;i<=n;i++)
    67     {
    68         bl[i]=(i-1)/blo+1;
    69         cnt[bl[i]].push_back(val[i]);
    70     } 
    71     for(int i=1;i<=bl[n];i++)
    72         sort(cnt[i].begin(),cnt[i].end());
    73     while(Q--)
    74     {
    75         scanf("%s",opt+1);
    76         int x=0,y=0,z=0;
    77         scanf("%d%d%d",&x,&y,&z);
    78         if(opt[1]=='M')
    79             add(x,y,z);
    80         else if(opt[1]=='A')
    81             printf("%d
    ",query(x,y,z));
    82     }
    83     return 0;
    84 }
    代码纯享版
     1 // luogu-judger-enable-o2
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cmath>
     5 #include<vector>
     6 
     7 using namespace std;
     8 
     9 int n,Q,blo;
    10 int val[1000090],bl[1000090],addtag[1000090];
    11 char opt[5];
    12 vector<int>cnt[5000];
    13 
    14 void update(int x)//针对散块 
    15 {//清空,重新读入 
    16     cnt[x].clear();
    17     for(int i=(x-1)*blo+1;i<=min(x*blo,n);i++)
    18         cnt[x].push_back(val[i]);
    19     sort(cnt[x].begin(),cnt[x].end());
    20 }
    21 
    22 void add(int l,int r,int p)
    23 {
    24     if(l==r) val[l]+=p;
    25     else
    26     {
    27         for(int i=l;i<=min(bl[l]*blo,r);i++)
    28             val[i]+=p;//左散块 
    29         update(bl[l]);//重新排序    
    30         if(bl[l]!=bl[r])
    31         {//右散块 
    32             for(int i=(bl[r]-1)*blo+1;i<=r;i++)
    33                 val[i]+=p;
    34             update(bl[r]);
    35         }
    36         //整块 
    37         for(int i=bl[l]+1;i<=bl[r]-1;i++)
    38             addtag[i]+=p;
    39     }
    40 }
    41 
    42 int query(int l,int r,int p)
    43 {
    44     int ans=0;
    45     //左半散块 
    46     for(int i=l;i<=min(bl[l]*blo,r);i++)
    47         if(val[i]+addtag[bl[l]]>=p) ans++;
    48     if(bl[l]!=bl[r])// !
    49     {//右半散块 
    50         for(int i=(bl[r]-1)*blo+1;i<=r;i++)
    51             if(val[i]+addtag[bl[r]]>=p) ans++;
    52     }
    53     for(int i=bl[l]+1;i<=bl[r]-1;i++)//整块 
    54     {
    55         int tmp=p-addtag[i];//求>=p,则先把加法标记减去 
    56         int pos=lower_bound(cnt[i].begin(),cnt[i].end(),tmp)-cnt[i].begin();
    57            ans+=blo-pos;//注意这句 精髓 
    58 //          ans+=find(i,tmp);
    59     }
    60     return ans;
    61 }
    62 
    63 int main()
    64 {
    65     scanf("%d%d",&n,&Q);
    66     for(int i=1;i<=n;i++) scanf("%d",&val[i]);
    67     blo=sqrt(n);
    68     for(int i=1;i<=n;i++)
    69     {
    70         bl[i]=(i-1)/blo+1;
    71         cnt[bl[i]].push_back(val[i]);//记录每个块中元素 
    72     } 
    73     //对每个块中元素进行排序 
    74     for(int i=1;i<=bl[n];i++)
    75         sort(cnt[i].begin(),cnt[i].end());
    76     while(Q--)
    77     {
    78         scanf("%s",opt+1);
    79         int x=0,y=0,z=0;
    80         scanf("%d%d%d",&x,&y,&z);
    81         if(opt[1]=='M')
    82             add(x,y,z);
    83         else if(opt[1]=='A')
    84             printf("%d
    ",query(x,y,z));
    85     }
    86     return 0;
    87 }
    贴心注释版

    然鹅不吸氧会T掉一个点,可能是我lowerbound常数的锅锅?讨论里有人说要用longlong结果我用了longlong只会带来无端的CE/WA/RE。

    Just be cautious.

  • 相关阅读:
    OC中的block
    tips: NSCopying和NSMutableCopying
    tips: @property 、@synthesize和@dynamic
    静态库SDK引发的符号冲突
    复杂业务app中跨业务页面调用方案
    AOP
    【HTML 初学】3、HTML标题
    【HTML 初学】2、HTML属性
    【HTML 初学】1、HTML元素
    【Java编程思想】二、一切都是对象
  • 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9642951.html
Copyright © 2011-2022 走看看