分块算法详解

本文详细介绍了分块算法的概念,包括如何分组、不同类型的区间操作如区间加法、单点查询等,并分析了时间复杂度。文章还讨论了分块算法与线段树的对比,以及在处理特定问题时的策略,如区间众数的求解。通过实例展示了分块算法在解决实际问题中的应用。
摘要由CSDN通过智能技术生成

一. 啥是分块

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

二. 分块的操作

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<bits/stdc++.h>
#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<bits/stdc++.h>
#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]);
    
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值