码迷,mamicode.com
首页 > 其他好文 > 详细

1zoj A simple problem with integer 2|板子|分块

时间:2018-12-03 16:29:19      阅读:230      评论:0      收藏:0      [点我收藏+]

标签:lld   分享   n个元素   基本   .com   const   线段   block   考试   

目录

分块算法

算法思想

引用某次考试Problem上的(伪)Pre reading(题解):

分块算法:
分块很像线段树,但是比线段树看起来更“暴力”一些,写起来更简单一些(期望得分80),用来维护复杂的区间信息时更容易一些。基本思想:可以把具有n个元素的集合分解成√n段,每一段的长度为√n (当然,最后一段可能不够)。对于任意一个区间操作[L,R],可将其分解成三部分。
技术分享图片
例如当n=16,L=3,R=10:
[L,R]区间可分解为:两端可能不足一个块长度的区域(1和3),和中间的若干完整块(2)。信息维护:对于中间的若干完整块,可以采取整体操作的方式(一般打lazytag),两边的零散块采用暴力的方式。
例如:区间修改
1、计算块长度len=√n
2、预处理单点所在的块编号b [i]=(i-1)/len+1 (若编号都是从1开始)
3、暴力更新左边[L,min(b [L]*len,R)], 中间打标记(从块b [L]+1到b [R]-1),暴力更新右边(可能不存在)。。。

板子题

技术分享图片

板子代码

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#define LL long long
using namespace std;
void read(LL &n){
    LL num=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        num=num*10+ch-'0';
        ch=getchar();
    }
    n=num*w;
}
const int maxn=1e5+5;
LL n,m;
int blo/*每个块的长度*/,bl[maxn];//每个块的编号
LL a[maxn],tag[maxn]/*懒标记*/,sum[maxn];
//预处理 
void init(){
    read(n);read(m);
    blo=sqrt(n);
    for(int i=1;i<=n;i++){
         read(a[i]);
         bl[i]=(i-1)/blo+1;//计算每个节点所在的块编号
         sum[bl[i]]+=a[i]; 
    }
}
//区间和查询 
LL query(int l,int r){
    LL ans=0;
    //暴力计算左边 
    for(int i=l;i<=min(bl[l]*blo,r);i++)
        ans+=a[i]+tag[bl[l]];
    //暴力计算右边 
    if(bl[l]!=bl[r])
        for(int i=(bl[r]-1)*blo+1;i<=r;i++)
            ans+=a[i]+tag[bl[r]];
    //整块计算中间
    for(int i=bl[l]+1;i<=bl[r]-1;i++)
        ans+=sum[i]+blo*tag[i];
    return ans;
}
//区间修改
void update(int l,int r,LL c){
    //暴力修改左边 
    for(int i=l;i<=min(bl[l]*blo,r);i++)
        a[i]+=c,sum[bl[l]]+=c;
    //暴力修改右边 
    if(bl[l]!=bl[r])
        for(int i=(bl[r]-1)*blo+1;i<=r;i++)
            a[i]+=c,sum[bl[r]]+=c;
    //整块修改中间
    for(int i=bl[l]+1;i<=bl[r]-1;i++)
        tag[i]+=c;
}
int main(){
    init();
    for(int i=1;i<=m;i++){
        char ord;cin>>ord;
        LL a,b;read(a);read(b);
        if(ord=='Q') printf("%lld\n",query(a,b)); 
        else{
            LL c;read(c);
            update(a,b,c);
        }
    }
    return 0;
}

1zoj A simple problem with integer 2|板子|分块

标签:lld   分享   n个元素   基本   .com   const   线段   block   考试   

原文地址:https://www.cnblogs.com/saitoasuka/p/10058994.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!