题目

https://loj.ac/p/6278

题解

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

对于任意一个无序数组,想要维护出该数组内小于某个值的元素个数,时间复杂度都将来到 \(O(n)\);对于任意一个有序数组,想要维护出该数组内小于某个值的元素个数,可以使用时间复杂度为 \(O(logn)\) 的二分法来维护。

对于每个块,都将数据拷贝到一个备份数组,随后将备份数组进行排序,单个块该操作时间复杂度为 \(O(\sqrt{n} + \sqrt{n}log\sqrt{n})\)。

若查询覆盖块 \(i\) 的全部元素,那么只需要对块 \(i\) 的备份数组进行二分查找出小于等于 \(c^2 - add[i]\) 的元素个数,单次操作时间复杂度 \(O(log\sqrt{n})\),此类块至多只有 \(\sqrt{n}\) 块,最差时间复杂度 \(O(\sqrt{n}log\sqrt{n})\);若查询未覆盖块 \(i\) 的全部元素,那么可以暴力维护出原数列小于等于 \(c^2 - add[i]\) 的元素个数,单次操作时间复杂度 \(O(\sqrt{n})\),此类块至多只有 \(2\) 块,最差时间复杂度 \(O(2\sqrt{n})\)。

对于区间加操作,将添加值存储在符合整块都进行加法操作的块的懒标记 \(add[i]\) 上,单次操作时间复杂度 \(O(1)\),此类块至多只有 \(\sqrt{n}\) 块,最差时间复杂度 \(O(\sqrt{n})\);未符合整块的进行加法操作则进行暴力处理,但是执行完加法后会破坏备份数组的有序性,需要重新备份且排序,单次操作时间复杂度 \(O(2\sqrt{n} + \sqrt{n}log\sqrt{n})\),此类块至多只有 \(2\) 块,最差时间复杂度 \(O(4\sqrt{n} + 2\sqrt{n}log\sqrt{n})\)。

参考代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long; int n;//数列元素个数
int op, l, r;
int len;//块长
ll c;
ll a[50005];//数列
ll b[50005];//排序后的数列
ll add[230];//懒添加标记
int lidx[230];//块的左下标
int ridx[230];//块的右下标 /*初始化块*/
void initPieces() {
len = sqrt(n);
memcpy(b + 1, a + 1, sizeof(ll) * n);//拷贝一份原数列
for (int i = 1, j = 1; i <= n; i += len, ++ j) {
lidx[j] = i;//左闭
ridx[j] = min(i + len, n + 1);//右开
sort(b + lidx[j], b + ridx[j]);//为当前块排序
}
} /*获取下标 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;
bool isLe = isLeftBoundary(l), isRi = isRightBoundary(r);
int le = getPieceId(l), ri = getPieceId(r);
if (op) {
int res = 0;
c = c * c;
for (int i = isLe ? le : le + 1, j = isRi ? ri : ri - 1; i <= j; ++ i) {
res += lower_bound(b + lidx[i], b + ridx[i], c - add[i]) - b - lidx[i];
}
if (!isLe) {
while (l <= r) {
res += a[l] + add[le] < c;
if (isRightBoundary(l)) break;
++ l;
}
}
if (!isRi) {
while (l <= r) {
res += a[r] + add[ri] < c;
if (isLeftBoundary(r)) break;
-- r;
}
}
cout << res << '\n';
} else {
for (int i = isLe ? le : le + 1, j = isRi ? ri : ri - 1; i <= j; ++ i) add[i] += c;
if (!isLe) {
//根号 n 时间复杂度重构第 le 块
while (l <= r) {
a[l] += c;
if (isRightBoundary(l)) break;
++ l;
}
memcpy(b + lidx[le], a + lidx[le], sizeof(ll) * (ridx[le] - lidx[le]));
sort(b + lidx[le], b + ridx[le]);
}
if (!isRi) {
//根号 n 时间复杂度重构第 ri 块
while (l <= r) {
a[r] += c;
if (isLeftBoundary(r)) break;
-- r;
}
memcpy(b + lidx[ri], a + lidx[ri], sizeof(ll) * (ridx[ri] - lidx[ri]));
sort(b + lidx[ri], b + ridx[ri]);
}
}
}
return 0;
}

【分块】LibreOJ 6278 数列分块入门2的更多相关文章

  1. LibreOJ 6278. 数列分块入门 2 题解

    题目链接:https://loj.ac/problem/6278 题目描述 给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,询问区间内小于某个值 \(x\) 的元素个数. ...

  2. LibreOJ 6278 数列分块入门 2(分块)

     题解:非常高妙的分块,每个块对应一个桶,桶内元素全部sort过,加值时,对于零散块O(sqrt(n))暴力修改,然后暴力重构桶.对于大块直接整块加.查询时对于非完整块O(sqrt(n))暴力遍历.对 ...

  3. LOJ #6278. 数列分块入门 2-分块(区间加法、查询区间内小于某个值x的元素个数)

    #6278. 数列分块入门 2 内存限制:256 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计测试数据讨论 6   题目描述 给出 ...

  4. #6278. 数列分块入门 2(询问区间内小于某个值 xx 的元素个数)

    题目链接:https://loj.ac/problem/6278 题目大意:中文题目 具体思路:数列分块模板题,对于更新的时候,我们通过一个辅助数组来进行,对于原始的数组,我们只是用来加减,然后这个辅 ...

  5. LibreOJ 6277. 数列分块入门 1 题解

    题目链接:https://loj.ac/problem/6277 题目描述 给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,单点查值. 输入格式 第一行输入一个数字 \( ...

  6. LibreOJ 6277. 数列分块入门 2

    题目链接:https://loj.ac/problem/6278 参考博客:https://blog.csdn.net/qq_36038511/article/details/79725027 这题我 ...

  7. LibreOJ 6277 数列分块入门 1(分块)

    题解:感谢hzwer学长和loj让本蒟蒻能够找到如此合适的入门题做. 这是一道非常标准的分块模板题,本来用打标记的线段树不知道要写多少行,但是分块只有这么几行,极其高妙. 代码如下: #include ...

  8. LOJ#6278. 数列分块入门 2

    在一个区间上进行操作,一种操作是某个小区间都加上c,另一个查找这个区间内大于c*c的数 我们可以另外开一个数组在保存a中的每个分块内的相对值,然后每次对a加值,并把a的值赋给b,不同的是b内的各个分块 ...

  9. LibreOJ 6285. 数列分块入门 9

    题目链接:https://loj.ac/problem/6285 其实一看到是离线,我就想用莫队算法来做,对所有询问进行分块,但是左右边界移动的时候,不会同时更新数字最多的数,只是后面线性的扫了一遍, ...

  10. LibreOJ 6282. 数列分块入门 6

    题目链接:https://loj.ac/problem/6282 参考博客:http://www.cnblogs.com/stxy-ferryman/p/8560551.html 这里如果用数组的话元 ...

随机推荐

  1. Wpf使用NLog将日志输出到LogViewer

    1 LogViewer LogViewer是通过UDP传输的高性能实时log查看器. 具有一下特性: 通过UDP读取日志 通过文件导入日志 导出日志到一个文件中 排序.过滤(日志树,日志等级)和查找 ...

  2. Win11本地部署FaceFusion3最强AI换脸,集成Tensorrt10.4推理加速,让甜品显卡也能发挥生产力

    FaceFusion3.0.0大抵是现在最强的AI换脸项目,分享一下如何在Win11系统,基于最新的cuda12.6配合最新的cudnn9.4本地部署FaceFusion3.0.0项目,并且搭配Ten ...

  3. 70.http拦截能做些什么(问的是axios的封装)

    请求拦截器统一添加 token ,也可以手动的判断token是否过期  : 响应拦截器判断返回数据的逻辑处理,被动的判断token过期并处理 :

  4. 妙用编辑器:把EverEdit变成计算器

    妙用编辑器:把EverEdit变成计算器 应用场景 日常工作过程中,会存在需要计算一些数据的场景,调用系统的计算器当然可以完成这项工作,但是需要来回切换,且系统自带的计算器没有表达式计算功能,真是不方 ...

  5. 云原生周刊:LitmusChaos 审计完成|2024.9.2

    开源项目推荐 Gardener Gardener 实现了 Kubernetes 集群的自动化管理和操作服务,并提供了一个经过完全验证的可扩展性框架,可以调整以适应任何编程云或基础设施提供商. Graf ...

  6. 图菱科技 SaaS 系统容器化最佳实践

    大家好,我是龚承明,在图菱(成都)科技有限公司任职,主要负责公司的产品系统研发以及公司IT基础设施的建设工作.本篇文章将为大家介绍下我司在采用 KubeSphere 平台实现公司业务系统容器化过程中的 ...

  7. RocketMQ 5.0 多语言客户端的设计与实现

    本文作者:古崟佑,阿里云中间件开发. RocketMQ 5.0 版本拥有非常多新特性,比如存储计算分离. batch 能力的提升等,它是具有里程碑意义的版本. 提到新版本,我们往往会首先想到服务端架构 ...

  8. OpenPSG:离AGI再进一步,首个开放环境关系预测框架 | ECCV'24

    全景场景图生成(PSG)的目标是对对象进行分割并识别它们之间的关系,从而实现对图像的结构化理解.以往的方法主要集中于预测预定义的对象和关系类别,因此限制了它们在开放世界场景中的应用.随着大型多模态模型 ...

  9. 深度学习系列之1----直观解释Transformer

    Abstract 这个系列主要用来记录我自己这种的AI小白的学习之路,通过将所学所知总结下来,记录下来.之前总喜欢记录在笔记本上,或者ipad上,或者PC端的Typora上,但总是很难回头检索到一些系 ...

  10. C++面经(持续更新)

    一. c,c++区别<九大点> c: 面向过程 c++: 面向对象(封装,继承,多态) 对象:对数据和作用于数据的操作组成的封装实体 类:描叙了一组有相同属性和方法的对象<虚拟> ...