• 【算法每日一练]-分块(保姆级教程 篇1)POJ3648


    插讲一下分块

            

            

    题目:(POJ 3648) 一个简单的整数问题

            

            

    前缀和往往用于静态的不会修改的区间和。遇到经常修改的区间问题,就要用分块或线段树来维护了。

    分块算法是优化后的暴力,分块算法有时可以维护一些线段树维护不了的东西,虽然效率一般不如线段树,但是比线段树更易上手。

             

             

    分块算法分3步骤:

            

    1,预处理块:处理块长(往往是根号n),每块的左右下标L[], R[],每块的区间和suf[],每个元素所属的块号pos[]

            

    2,区间修改:对于完整的块仅修改懒标记,不完整的就暴力修改a[]和suf[]

            

    3,区间查询 :对于完整的块直接利用懒和suf,不完整的就暴力

            

    1. #include //POJ3648
    2. using namespace std;
    3. const int N=100010;
    4. typedef long long ll;
    5. ll a[N],suf[N],add[N];
    6. int L[N],R[N],pos[N];
    7. int n,m,t,l,r,d;
    8. char op[3];
    9. //分块预处理:(我们处理下标都是从1开始)
    10. void build(){//处理t块长,L[]R[]每块的左右下标,pos[]每个下标的所属块号,suf[]每块的和
    11. t=sqrt(n*1.0);
    12. int num=n/t;
    13. if(n%t) num++;
    14. for(int i=1;i<=num;i++){
    15. L[i]=(i-1)*t+1;
    16. R[i]=i*t;
    17. }
    18. R[num]=n;//更改最后一块的右下标
    19. for(int i=1;i<=num;i++){
    20. for(int j=L[i];j<=R[i];j++){
    21. pos[j]=i;
    22. suf[i]+=a[j];
    23. }
    24. }
    25. }
    26. //区间修改
    27. void change (int l,int r,ll d){//修改add[]懒标,a[]和suf[]
    28. int p=pos[l],q=pos[r];
    29. if(p==q){//如果在同一块就暴力修改a[]和suf[]
    30. for(int i=l;i<=r;i++) a[i]+=d;
    31. suf[p]+=d*(r-l+1);
    32. }
    33. else{//完整的块仅修改懒标,不完整就暴力
    34. for(int i=p+1;i<=q-1;i++) add[i]+=d;
    35. for(int i=l;i<=R[p];i++) a[i]+=d;
    36. suf[p]+=d*(R[p]-l+1);
    37. for(int i=L[q];i<=r;i++) a[i]+=d;
    38. suf[q]+=d*(r-L[q]+1);
    39. }
    40. }
    41. ll query(int l,int r){
    42. int p=pos[l],q=pos[r];
    43. ll ans=0;
    44. if(p==q){//同一块就暴力
    45. for(int i=l;i<=r;i++) ans+=a[i];
    46. ans+=add[p]*(r-l+1);
    47. }
    48. else{//完整就suf+add,不完整就暴力
    49. for(int i=p+1;i<=q-1;i++) ans+=suf[i]+add[i]*(R[i]-L[i]+1);
    50. for(int i=l;i<=R[p];i++) ans+=a[i];
    51. for(int i=L[q];i<=r;i++) ans+=a[i];
    52. ans+=add[q]*(r-L[q]+1);
    53. }
    54. return ans;
    55. }
    56. int main(){
    57. cin>>n>>m;
    58. for(int i=1;i<=n;i++){
    59. scanf("%lld",&a[i]);
    60. }
    61. build();
    62. for(int i=1;i<=m;i++){
    63. scanf("%s %d %d",op,&l,&r);
    64. if(op[0]=='C'){
    65. scanf("%d",&d);
    66. change(l,r,d);
    67. }
    68. else{
    69. printf("%lld\n",query(l,r));
    70. }
    71. }
    72. }

     

  • 相关阅读:
    linux的基本指令(中)
    C++修炼之路之继承<二>
    openssl学习——消息认证码原理
    尚硅谷大数据hadoop教程_HDFS
    堆 堆排序 TopK问题
    基于matlab实现的弹簧振动系统模型程序(动态模型)
    ITSS认证审核时相关问题与解答
    SwiftUI Bluetooth 使用
    在 JdbcTemplate IN 子句中使用List动态参数
    Element - el-table 表头列字段筛选 支持一个页面多table
  • 原文地址:https://blog.csdn.net/m0_69478376/article/details/134386940