首页 > 其他分享 >【分块】LibreOJ 6277 数列分块入门1

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

时间:2024-11-22 21:06:58浏览次数:1  
标签:6277 LibreOJ 分块 int len add sqrt 数列

前言

分块是一种优雅的暴力,将数组按块长 \(\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;
}

标签:6277,LibreOJ,分块,int,len,add,sqrt,数列
From: https://www.cnblogs.com/RomanLin/p/18556509

相关文章

  • 分块莫队学习笔记
    优雅的暴力。引入link。这道题显然可以用线段树、树状数组做,但如果我偏不用这些数据结构呢?我们知道,暴力修改和查询最坏是\(\mathcal{O}(n)\)的,这样肯定会挂掉。那该怎么办呢?正题分块考虑将序列分成若干块,我们设每块长为\(B\)。对于每次查询\(\left[l,r\right]......
  • [ABC339G] Smaller Sum(分块 卡常 qwq)
    link和数列分块入门2差不多的思路,对每个块排序,然后就可以在上面二分,求和,发现都是在二分出来的位置前面的数,可以用前缀和预处理出来分块按照一般分法n,q同阶,时间复杂度是\(O(n\sqrt{n}\log\sqrt{n})\)然后交上去发现最后几个点T了,算一下,大概是2e5*450*8=7e8,时......
  • 20240923 分块莫队专题
    20240923分块莫队专题回滚莫队回滚莫队适用于添加与删除中有一种较为困难的情况。大致思想如下:对原序列分块,将询问按左端点所在块编号排序,同一块内按右端点排序。对每个块,视情况初始化左右指针,扫一遍询问。先移动右指针到询问右端点,记录当前状态的答案,再将左指针移到询问左端......
  • markdown矩阵分块和latex中矩阵分块记录
    1.markdown中常见的符号附件\hat{X}\widehat{X}\check{X}\breve{X}\tilde{X}\dot{X}\ddot{X}\overline{X}\underline{X}2.markdown中矩阵由\left[ right],\begin{array}{ccc}\end{array}包围,分行由\\实现,分列通过ccc固定列数,列与列间用&分割代码:\left[\begin......
  • 408数据结构-折半查找,分块查找 自学知识点整理
    前置知识:查找的基本概念折半查找折半查找又称二分查找,它仅适用于有序的顺序表。因个人习惯,下文均用二分代替折半。二分查找的基本思想:首先将给定值ke......
  • 数论分块
    数论分块讲解先咕咕,做杜教筛做错题了做了个数论分块,下次再讲。题目示例P3327[SDOI2015]约数个数和设\(d(x)\)为\(x\)的约数个数,给定\(n,m\),求\[\sum_{i=1}^n\sum_{j=1}^md(ij)\]对于\(100\%\)的数据,\(1\leT,n,m\le50000\)。\[\sum_{i=1}^n\sum_{j=1}^md(ij)=......
  • LOJ 数列分块入门2
    算法考虑求小于给定值的数的个数,可以给每个块再维护一个已经排好序的数组,整块加法对于这个块排好序的数组没有影响,零散块加法直接在原序列上加,再将零散块所处的整块从新排序。查询时零散块暴力查找,整块二分查找代码#include<bits/stdc++.h>#defineintlonglongconstintM......
  • P6277 [USACO20OPEN] Circus P
    做法来自浙江队长,因为其他的题解我一篇都看不懂。考察一条极长的二度链C,即左右端点度数不为\(2\),中间的点度数都等于\(2\),它把整张图分成了左右两部分A和B(端点既属于AB也属于C)。如果\(|C|\gen-k\),那么A和B都一定被占满了,C上的点一定会阻挡A和B之间互换,所......
  • 【JS】requestIdleCallback实现分块执行
    点击按钮后,执行一个耗时较长的dom操作,页面很长时间没有响应,给用户一种卡死的现象<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0">&......
  • 张量矩阵乘法分块乘法概述
    张量矩阵乘法分块乘法概述介绍一下矩阵计算相关的内容,从最基本的算法,到Cutlass这些线性代数模版库,特别是Layout代数相关的内容,再逐渐细化到一些硬件实现访存优化和一些算子融合。6.3.1GEMM概述1.GEMM定义对于一个矩阵乘法,定义如下: (6-1)一个矩阵乘法定义,如图6-26......