【学习笔记】 分块

【学习笔记】分块

算法简介

分块是一种优雅的暴力,他的实现原理是将一段区间分割成一些长度相等的整块和一些散块进行暴力,有点类似线段树。
每一次操作时将区间分成中间的一些整块,和两端的一些散块。举一个例子,假设我们要对区间[2,10]进行操作,假设整块的块长为3,那么整个大区间就可以分为[2,3],[4,6],[7,9],[10,10]这几个区间
进行操作。
再来分析复杂度,设块长为B,区间总长为n,则单次操作O(nb+b),分别为处理散块时的复杂度,和处理整块时的复杂度,由基本不等式可得最优为O(n),总的最优为O(n×n), 此时块长为n

code

需要求出
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;
}
posted @   GuoSN0410  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示