分块

分块算法的思想是通过适当的划分,通过预处理,用空间换取时间,达到时空平衡

基本操作是,将一段序列,分成一定数量的块,每一块有一个长度,表示一段区间
一般来讲,块的大小常设为$\sqrt{n}$,但实际上块的大小可以任意自定,不过肯定是要让复杂度尽可能的低
分块的效率虽然低于树状数组和线段树,但代码实现相对简单,也更好理解
但是俗话说的好:越简单的东西,就意味着它越牢固,可拓展性越强

用法

  分块支持区间修改和区间查询,与其说是数据结构,它其实更像是一种思想,相当于分治的一个分支。

分块的基本操作:
  划分块,预处理,操作或查询
  操作或查询通常为4步:
    1. 判断要操作或是查询的区间是否只在一个块内
    2. 若只在一个块内,暴力操作或查询
    3. 若不只在一个块内,将除了最左边和最右边这两个块外,其余中间的整块进行整体的操作,即直接对块打上修改标记
    4. 单独暴力处理左边剩余的碎块和右边剩余的碎块

  即“左碎+整块+右碎”,“单点+区间+单点”解决区间的修改与查询问题

常用数组意义及用法:

//就按照自己的习惯来了
struct dian{
    long long zhi;//该点当前的数值
    int k;//该点所在的块的编号 
};
dian a[NUM];
long long sum[NUM];//第i个块中所有点的总和
long long tag[NUM];//第i个块的懒惰标记
int n;
int w;//每个块里点的数量 
void add( int l,int r,int p );
void query( int l,int r );
int main(){
    cin >> n;
    w = sqrt(n);
    for( int i = 1;i <= n;i++ ){
        cin >> a[i].zhi;
        a[i].k = (i-1) / w + 1;//第i个点所在的块编号 
        sum[a[i].k] += a[i].zhi;
    }
    int l,r,p;
    cin >> l >> r >> p;
    add( l,r,p );//区间修改 
    query( l,r );//区间查询 
} 
void add( int l,int r,int p ){ //区间加 
    for( int i = l;i <= min(r,a[l].k * w);i++ ){ //左边的碎块
    //l是增值的起点, a[l].k * w是起点所在块的最后一个 
    //取min是预防r与l在一个块里 
        a[i].zhi += p; //点本身加 
        sum[a[i].k] += p;//点所在块加 
    }
    if( a[l].k != a[r].k ){  //如果起点终点不在同一个块,那就说明有右碎块 
        for( int i = (a[r].k-1)*w+1;i <= r;i++ ){ //从右碎块的前一个块的结尾的后一个点开始,即碎块的第一个
            a[i].zhi += p; //同左碎块 
            sum[a[i].k] += p;
        }
    }
    for( int i = a[l].k+1;i <= a[r].k-1;i++ ) //整块是除去起点所在块与终点所在块的中间所有块 
        tag[i] += p; //整块直接加在懒惰标记上 
}
void query( int l,int r ){ //查询
    //其实大体结构跟add函数差不多 
    long long ans = 0;
    for( int i = l;i <= min(r,a[l].k * w);i++ ) //左边的碎块
        ans += a[i].zhi + tag[a[i].k]; //一个点的真实值为本身值加所在块的懒惰标记值 
    if( a[l].k != a[r].k ){ 
        for( int i = (a[r].k-1)*w+1;i <= r;i++ ) //右边的碎块 
            ans += a[i].zhi + tag[a[i].k];
    }
    for( int i = a[l].k+1;i <= a[r].k-1;i++ ) //整块
        ans += sum[i] + tag[i] * w;//懒惰标记是每个人都有的,所以要乘以成员数量 
}

分块的用法板子
分块用法板子

 

以题目作为一个例子,具体感受分块的用法及精髓:洛谷P2357守墓人 题解

 

posted @ 2022-02-08 21:28  little_sheep_xiaoen  阅读(55)  评论(0编辑  收藏  举报