【算法模板】数据结构:分块

概念

严谨来说,分块是一种思想,而不是一种数据结构。

分块的基本思想是,通过对原数据的适当划分,并在划分后的每一个块上预处理部分信息,从而较一般的暴力算法取得更优的时间复杂度。

分块的时间复杂度主要取决于分块的块长,一般可以通过均值不等式求出某个问题下的最优块长,以及相应的时间复杂度,我们一般取根号相关的值。

分块是一种很灵活的思想,相较于树状数组和线段树,分块的优点是通用性更好,可以维护很多树状数组和线段树无法维护的信息。

模板

int Bnum; // 得到每个组的元素的数量
int get_gid(int x) {
    return x / Bnum;
}
int get_gl(int x) {
    return max(get_gid(x) * Bnum, 1);
} 
int get_gr(int x) {
    return min(get_gid(x) * Bnum + Bnum - 1, n);
}

例题

单点修改,区间查询

单点修改,区间查询 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
using namespace std;
int main() {
    int n;
    cin >> n;
    int T = ceil(sqrt(n));
    vector<int> v(n + 1);
    for (int i = 1; i <= n; i++)cin >> v[i];
    vector<int> vt(n / T+1);
    for (int i = 1; i <= n; i++)vt[i / T] += v[i];
    int m;
    cin >> m;
    while (m--) {
        int ch;
        cin >> ch;
        if (ch == 1) {
            int x, a;
            cin >> x >> a;
            v[x] += a;
            vt[x / T] += a;
        } else {
            int a, b;
            cin >> a >> b;
            int sum = 0;
            if (a / T == b / T)for (int i = a; i <= b; i++)sum += v[i];
            else {
                for (int i = a; i < a / T * T + T; i++)sum += v[i];
                for (int i = a / T + 1; i < b / T; i++)sum += vt[i];
                for (int i = b / T * T; i <= b; i++)sum += v[i];
            }
            cout << sum << endl;
        }
    }
    return 0;
}

区间修改、区间求和

区间修改、区间求和 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main(){
    int n,q;cin>>n>>q;
    int t=ceil(sqrt(n));
    vector<int> arr(n+1);
    vector<int> sum(n/t+1);
    vector<int> add(n/t+1);
    for(int i=1;i<=n;i++)cin>>arr[i],sum[i/t]+=arr[i];
    while(q--){
        int choice;cin>>choice;
        if(choice==1){
            int l,r,k;
            cin>>l>>r>>k;
            if(l/t==r/t) {
                for(int i=l;i<=r;i++)arr[i]+=k;
                sum[l/t]+=(r-l+1)*k;
            }
            else{
                for(int i=l;i<l/t*t+t;i++)arr[i]+=k,sum[l/t]+=k;
                for(int i=l/t+1;i<r/t;i++)add[i]+=k;
                for(int i=r/t*t;i<=r;i++)arr[i]+=k,sum[r/t]+=k;
            }
        }
        else{
            int l,r;cin>>l>>r;
            int ans=0;
            if(l/t==r/t) {
                for(int i=l;i<=r;i++)ans+=arr[i]+add[i/t];
            }
            else{
                for(int i=l;i<l/t*t+t;i++)ans+=arr[i]+add[i/t];
                for(int i=l/t+1;i<r/t;i++)ans+=sum[i]+add[i]*t;
                for(int i=r/t*t;i<=r;i++)ans+=arr[i]+add[i/t];
            }
            cout<<ans<<endl;
        }
    }
    return 0;
}

区间最大值

区间最大值 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
using namespace std;
signed main(){
    int n,q;cin>>n>>q;
    int t=ceil(sqrt(n));
    vector<int> arr(n+1);
    vector<int> vmax(n/t+1);
    for(int i=1;i<=n;i++){
        cin>>arr[i];
        vmax[i/t]=max(vmax[i/t],arr[i]);
    }
    while (q--){
        int l,r;cin>>l>>r;
        int ans=-1e9;
        if(l/t==r/t)for(int i=l;i<=r;i++)ans=max(ans,arr[i]);
        else{
            for(int i=l;i<l/t*t+t;i++)ans=max(ans,arr[i]);
            for(int i=l/t+1;i<r/t;i++)ans=max(ans,vmax[i]);
            for(int i=r/t*t;i<=r;i++)ans=max(ans,arr[i]);
        }
        cout<<ans<<endl;
    }
    return 0;
}

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值