分块算法详解

分块算法详解

  • 一. 啥是分块
  • 二. 分块的操作
    • 1. 分组
    • 2. 区间加法&单点查询
    • 3.区间加法&询问区间内小于某个值 x 的元素个数
    • 4.区间求和&区间加法
    • 5.区间开方&区间求和
    • 6. 单点插入&单点询问
    • 7. 区间加法&区间前驱
    • 8. 区间乘法&区间加法&单点询问
    • 9.区间某值个数&区间赋值
    • 10.区间众数
  • 三. 分块算法时间复杂度分析
    • 1. 时间复杂度
    • 2. 万恶的卡常
  • 四. 分块算法与线段树对比
  • 五. 例题

一. 啥是分块

分块,顾名思义,就是把一个东西分成多个块来进行维护操作,也被称为优雅的暴力。

二. 分块的操作

1. 分组

我们设数组长度为 N N N ,分成 K K K 块,每块长度 N K \dfrac{N}{K} KN 。对于一次区间操作,对区间內部的整块进行整体的操作,对区间边缘的零散块单独暴力处理。

所以,块数不能太少也不能太多。所以,一般来说,我们取得块长(块的长度)为 N \sqrt{N} N 。这样我们的时间复杂度即为带 N \sqrt N N 的。这是一种根号算法。

尽管比不上线段树以及树状数组,但是分块的可灵活性,但不用一层一层传数据的特性,让分块算法更加难以模板化

分块代码:

int block=sqrt(n); //块长
for(int i=1;i<=n;i++)
{
   
	belong[i]=(i-1)/block+1; //每一个位置的分组
}

2. 区间加法&单点查询

我们可以先将区间首位和末位的余块(不完全的块)暴力加上一个数。中间完整的块可以维护一个 tag ⁡ \operatorname{tag} tag 数组,加上一个数的时候把 tag ⁡ \operatorname{tag} tag 数组也加上这个数。最后输出的时候把原数加上 tag ⁡ \operatorname{tag} tag

代码:

#include
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int Maxn=5e4+10;
int belong[Maxn];
int Ar[Maxn];
int tag[Maxn];
int main()
{
   
    int n;
    scanf("%d",&n);
    int block=sqrt(n);
    for(int i=1;i<=n;i++)
    {
   
        scanf("%d",&Ar[i]);
    }
    for(int i=1;i<=n;i++)
    {
   
        belong[i]=(i-1)/block+1;
    }
    for(int i=1;i<=n;i++)
    {
   
        int opt,l,r,c;
        scanf("%d%d%d%d",&opt,&l,&r,&c);
        if(opt==0)
        {
   
            for(int i=l;i<=min(belong[l]*block,r);i++)
            {
   
                Ar[i]+=c;
            }
            if(belong[l]!=belong[r])
            {
   
                for(int i=(belong[r]-1)*block+1;i<=r;i++)
                {
   
                    Ar[i]+=c;
                }
            }
            for(int i=belong[l]+1;i<=belong[r]-1;i++)
            {
   
                tag[i]+=c;
            }
        }else{
   
            printf("%d\n",Ar[r]+tag[belong[r]]);
        }
    }
    return 0;
}

3.区间加法&询问区间内小于某个值 x 的元素个数

利用上一题的思想,可以先处理出 tag ⁡ \operatorname{tag} tag 数组,然后维护一个 G ⁡ \operatorname{G} G vector ⁡ \operatorname{vector} vector 数组,利用 lower ⁡ bound ⁡ \operatorname{lower}\operatorname{bound} lowerbound 函数求出。

#include
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
#define int long long
 
const int Maxn=5e4+10;
int belong[Maxn];
int n;
int block;
long long Ar[Maxn];
int tag[Maxn];
vector<int> G[Maxn];
void reset(int x)
{
   
    G[x].resize(0);
    for(int i=(x-1)*block+1;i<=min(x*block,n);i++)
    {
   
        G[x].push_back(Ar[i]);
    

你可能感兴趣的:(C++,数据结构,C++算法,数据结构,关键字,数据结构,算法)