【学习笔记】 分块
【学习笔记】分块
算法简介
分块是一种优雅的暴力,他的实现原理是将一段区间分割成一些长度相等的整块和一些散块进行暴力,有点类似线段树。
每一次操作时将区间分成中间的一些整块,和两端的一些散块。举一个例子,假设我们要对区间进行操作,假设整块的块长为,那么整个大区间就可以分为这几个区间
进行操作。
再来分析复杂度,设块长为,区间总长为,则单次操作,分别为处理散块时的复杂度,和处理整块时的复杂度,由基本不等式可得最优为,总的最优为, 此时块长为
需要求出
1.每个元素所属块的编号
2.对于整个块的操作
3.对于单个元素的操作
#include<bits/stdc++.h>
#define maxn 100010
#define ll long long
using namespace std;
int n, m, sz, tot = 0;
ll L[maxn], R[maxn], add[maxn], sum[maxn], a[maxn];
int bel[maxn];
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> n >> m;
for(int i = 1; i <= n; i++){
cin >> a[i];
}
sz = sqrt(n);
if(n % sz) tot = n / sz + 1;
else tot = n / sz;
for(int i = 1; i <= tot; i++){
L[i] = sz * (i - 1) + 1;
R[i] = min(sz * i, n);
}
for(int i = 1; i <= n; i++){
bel[i] = (i - 1) / sz + 1;
sum[bel[i]] += a[i];
}
for(int i = 1; i <= m; i++){
ll op, l, r, k;
cin >> op >> l >> r;
if(op == 1){
cin >> k;
if(bel[l] == bel[r]){
for(int i = l; i <= r; i++){
sum[bel[i]] += k;
a[i] += k;
}
}
else{
for(int i = bel[l] + 1; i < bel[r]; i++){
sum[i] += sz * k;
add[i] += k;
}
for(int i = l; i <= R[bel[l]]; i++){
a[i] += k;
sum[bel[i]] += k;
}
for(int i = L[bel[r]]; i <= r; i++){
a[i] += k;
sum[bel[i]] += k;
}
}
}
else{
ll ans = 0;
if(bel[l] == bel[r]){
for(int i = l; i <= r; i++){
ans += a[i] + add[bel[i]];
}
}
else{
for(int i = bel[l] + 1; i < bel[r]; i++){
ans += sum[i];
}
for(int i = l; i <= R[bel[l]]; i++){
ans += a[i] + add[bel[i]];
}
for(int i = L[bel[r]]; i <= r; i++){
ans += a[i] + add[bel[i]];
}
}
cout << ans << endl;
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】