• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

RomanLin

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

【分块】LibreOJ 6277 数列分块入门1

前言

分块是一种优雅的暴力,将数组按块长 \(\sqrt{n}\) 进行分块,可实现区间加法、区间求和和区间逆序对计数等场景,进行 \(m\) 次操作的时间复杂度:\(O(m\sqrt{n})\)。

对于整个块都进行操作,可以用打上标记的方式来取代操作这个块的全部元素,由于最多只需要处理 \(\sqrt{n}\) 个块,因此这个操作的时间复杂度是 \(O(\sqrt{n})\)。对于不属于整个块的部分,直接进行暴力处理,易知这样子的块最多只有两个,需要处理的元素至多只有 \(2 * \sqrt{n} - 2\) 个,因此这步操作时间复杂度也是 \(O(\sqrt{n})\)。

题目

https://loj.ac/p/6277

题解

将 \(n\) 个元素的数组 \(a\) 按块长 \(\sqrt{n}\) 进行分块处理。为每个块设置一个懒添加标记 \(add[i]\),代表这个区间每个元素共同添加的数值大小。

对于 \(opt = 0\) 的情况:将添加值存储在符合整块都进行加法操作的块的懒标记 \(add[i]\) 上,未符合整块都进行加法操作则进行暴力处理。
对于 \(opt = 1\) 的情况:直接输出 \(a[r] + add[getPieceId(r)]\)。

参考代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

int n;//数列元素个数
int op, l, r, c;
int len;//块长
ll a[50005];//数列
ll add[230];//每个块的懒添加标记

/*初始化块*/
void initPieces() {
	len = sqrt(n);
}

/*获取下标 x 所在的块的索引*/
int getPieceId(int x) {
	return (x - 1) / len + 1;
}

/*判断下标 x 是否为块的左边界*/
bool isLeftBoundary(int x) {
	return (x - 1) % len == 0;
}

/*判断下标 x 是否为块的右边界*/
bool isRightBoundary(int x) {
	return x % len == 0;
}

int main() {
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	cin >> n;
	for (int i = 1; i <= n; ++ i) cin >> a[i];
	initPieces();
	for (int i = 0; i < n; ++ i) {
		cin >> op >> l >> r >> c;
		if (op) {
			cout << a[r] + add[getPieceId(r)] << '\n';
		} else {
			bool isLe = isLeftBoundary(l), isRi = isRightBoundary(r);
			int le = getPieceId(l), ri = getPieceId(r);
            //首先处理整块的内容
			for (int i = isLe ? le : le + 1, j = isRi ? ri : ri - 1; i <= j; ++ i) add[i] += c;
			//其次处理左边不满一块的内容
            if (!isLe) {
				while (l <= r) {
					a[l] += c;
					if (isRightBoundary(l)) break;
					++ l;
				}
			}
            //最后处理右边不满一块的内容
			if (!isRi) {
				while (l <= r) {
					a[r] += c;
					if (isLeftBoundary(r)) break;
					-- r;
				}
			}
		}
	}
	return 0;
}

posted on 2024-11-22 21:15  RomanLin  阅读(79)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3