题目链接:https://loj.ac/problem/6278

题目描述

给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,询问区间内小于某个值 \(x\) 的元素个数。

输入格式

第一行输入一个数字 \(n\)。

第二行输入 \(n\) 个数字,第 \(i\) 个数字为 \(a_i\),以空格隔开。

接下来输入 \(n\) 行询问,每行输入四个数字 \(opt\)、\(l\)、\(r\)、\(c\),以空格隔开。

若 \(opt=0\),表示将位于 \([l,r]\) 的之间的数字都加 \(c\)。

若 \(opt=1\),表示询问 \([l,r]\) 中,小于 \(c^2\) 的数字的个数。

输出格式

对于每次询问,输出一行一个数字表示答案。

样例输入

  1. 4
  2. 1 2 2 3
  3. 0 1 3 1
  4. 1 1 3 2
  5. 1 1 4 1
  6. 1 2 3 2

样例输出

  1. 3
  2. 0
  3. 2

解题思路

同样还是按照每个块的大小为 \(\lfloor \sqrt{n} \rfloor\) 来进行分块。

这里我们同样用 \(p[i]\) 来表示 \(a[i]\) 所属的分块编号,用 \(v[k]\) 来表示第 \(k\) 个分块的累计更新值。

于此同时,我们再开一个数组 \(b[i]\) ,\(b\) 数组其实就是 \(a\) 数组的一个映射。那么它是怎么映射的呢?

我们假设 \(a[l..r]\) 属于同一个分块,且 \(a[l] 是这个分块的第一个元素,\)a[r$ 是这个分块的最后一个元素,那么 \(b[l..r]\) 就是 \(a[l..r]\) 排好序的结果,即:

  • \(b[l]\) 对应 \(a[l..r]\) 中最小的元素;
  • \(b[l+1]\) 对应 \(a[l..r]\) 中次小的元素;
  • ……
  • \(b[r]\) 对应 \(a[l..r]\) 中最大的元素。

一旦我们修改了某一个分块 \(k\) 中的部分元素,就需要将分块 \(k\) 对应的 \(b\) 数组的这段区间排序(对于分块 \(k\),它对应的坐标范围应该是 \([(k-1) \times m + 1, \min(k \times m, n)]\))。

修改操作:

  • 如果区间没有完整覆盖分块 \(k\),则遍历次分块中的每一个元素,令 \(a[i]+=c\);
  • 否则(完整覆盖分块 \(k\)),则令 \(v[k] += c\)。

查询操作:

  • 如果区间没有完整覆盖分块 \(k\),则遍历次分块中的每一个元素,判断 \(a[i] \lt c^2-v[p[i]]\) 是否成立;
  • 否则(完整覆盖分块 \(k\)),因为 \(b\) 数组具有单调性,对分块 \(k\) 包含的区间范围内的 \(b[l..r]\) 进行二分获取有多少元素 \(b[i] \lt c^2-v[k]\)。

最后将答案汇总。

每次修改的时间复杂度为 \(O( \sqrt{n} )\);

每次查询的时间复杂度为 \(O( \sqrt{n} \times \sqrt{ \sqrt{n} } ) = O(n^{ \frac 34 })\) ,

因为总共有有 \(n\) 次操作,所以整的时间复杂度为 \(O(n \times n^{ \frac 34 })\) 。

实现代码如下:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int maxn = 50050;
  4. int n, m, a[maxn], b[maxn], p[maxn], v[300], op, l, r, c;
  5. void update_part(int pid) {
  6. int i1 = (pid-1)*m+1, i2 = min(pid*m+1, n+1); // 一定要注意边界条件,我在这里RE了好久,因为最后一个分块长度不一定是m
  7. for (int i = i1; i < i2; i ++)
  8. b[i] = a[i];
  9. sort(b+i1, b+i2);
  10. }
  11. void add(int l, int r, int c) {
  12. if (p[l] == p[r]) { // 说明在同一个分块,直接更新
  13. for (int i = l; i <= r; i ++) a[i] += c;
  14. update_part(p[l]);
  15. return;
  16. }
  17. if (l % m != 1) { // 说明l不是分块p[l]的第一个元素
  18. for (int i = l; p[i]==p[l]; i ++) {
  19. a[i] += c;
  20. }
  21. update_part(p[l]);
  22. }
  23. else v[p[l]] += c;
  24. if (r % m != 0) { // 说明r不是分块p[r]的最后一个元素
  25. for (int i = r; p[i]==p[r]; i --)
  26. a[i] += c;
  27. update_part(p[r]);
  28. }
  29. else v[p[r]] += c;
  30. for (int i = p[l]+1; i < p[r]; i ++)
  31. v[i] += c;
  32. }
  33. int count_part(int pid, int c) {
  34. int i1 = (pid-1)*m+1, i2 = min(pid*m+1, n+1);
  35. int cnt = lower_bound(b+i1, b+i2, c*c-v[pid]) - (b+i1);
  36. return cnt;
  37. }
  38. int get_count(int l, int r, int c) {
  39. int cnt = 0;
  40. if (p[l] == p[r]) { // 说明在同一个分块,直接更新
  41. for (int i = l; i <= r; i ++)
  42. if (a[i]+v[p[i]] < c*c)
  43. cnt ++;
  44. return cnt;
  45. }
  46. if (l % m != 1) { // 说明l不是分块p[l]的第一个元素
  47. for (int i = l; p[i]==p[l]; i ++)
  48. if (a[i]+v[p[i]] < c*c)
  49. cnt ++;
  50. }
  51. else cnt += count_part(p[l], c);
  52. if (r % m != 0) { // 说明r不是分块p[r]的最后一个元素
  53. for (int i = r; p[i]==p[r]; i --)
  54. if (a[i]+v[p[i]] < c*c)
  55. cnt ++;
  56. }
  57. else cnt += count_part(p[r], c);
  58. for (int i = p[l]+1; i < p[r]; i ++)
  59. cnt += count_part(i, c);
  60. return cnt;
  61. }
  62. int main() {
  63. scanf("%d", &n);
  64. m = sqrt(n);
  65. for (int i = 1; i <= n; i ++) p[i] = (i-1)/m + 1;
  66. for (int i = 1; i <= n; i ++) scanf("%d", &a[i]);
  67. for (int i = m; i <= n; i += m) update_part(p[i]); // 初始化所有完整的块
  68. for (int i = 0; i < n; i ++) {
  69. scanf("%d%d%d%d", &op, &l, &r, &c);
  70. if (op == 0) add(l, r, c);
  71. else printf("%d\n", get_count(l, r, c));
  72. }
  73. return 0;
  74. }

LibreOJ 6278. 数列分块入门 2 题解的更多相关文章

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

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

  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. LibreOJ6279. 数列分块入门 3 题解

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

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

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

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

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

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

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

  8. LibreOJ 6282 数列分块入门 6(在线插入在线查询)

    题解:还是分块,将每个块存入vector,然后在插入的时候就是sqrt(n)级的重构,如果块太大了,暴力将这个块拆开. 代码如下: #include<cmath> #include< ...

  9. LibreOJ 6280 数列分块入门 4(分块区间加区间求和)

    题解:分块的区间求和比起线段树来说实在是太好写了(当然,复杂度也高)但这也是没办法的事情嘛.总之50000的数据跑了75ms左右还是挺优越的. 比起单点询问来说,区间询问和也没有复杂多少,多开一个su ...

随机推荐

  1. HZOJ string

    正解炸了…… 考试的时候想到了正解,非常高兴的打出来了线段树,又调了好长时间,对拍了一下发现除了非常大的点跑的有点慢外其他还行.因为复杂度算着有点高…… 最后正解死于常数太大……旁边的lyl用同样的算 ...

  2. day5_python之subprocess模块

    subprocess作用:用来执行系统命令它会开启一个子进程,通过子进程去执行一些命令 读取正确的命令执行结果,如果没有指定把结果输出到哪里,默认打印到屏幕上 #subprocess.Popen(r' ...

  3. Fiddler快速入门

    Fiddler是一个免费.强大.跨平台的HTTP抓包工具.Wireshark也是一个强大的抓包工具,不过Wireshark是一个通用的抓包工具,主要精力放在各种协议上了,针对HTTP的特定功能较少.所 ...

  4. 使用react-tooltip实现鼠标悬浮显示框详细记录

    前段时间遇到的一个需求,要求鼠标悬停显示使用描述, 用到了react-tooltip插件,今天写一个总结 先看效果(为了方便参考,用的是原始样式): 文档参考地址: https://www.npmjs ...

  5. H3C 帧中继基本配置命令(续)

  6. 如何检查linux是否安装了php

    方法一.在终端通过php -v命令来查看一下当前php的版本.如果没有安装php,一般会提示没有php这个命令的. 2 方法二.在终端查询安装的包中是否有php,以redhat为例,则可以执行如下命令 ...

  7. Python--day62--Django安装,配置,web请求流程,views.py总结

    1,安装Django 2,创建Django项目: 3,配置Django项目 1.settinngs.py文件 1.templates文件夹的位置 2.静态文件 1,STATIC_URL   ----- ...

  8. dos taskkill 命令

    C:\Users\asn\Desktop>taskkill /? TASKKILL [/S system [/U username [/P [password]]]] { [/FI filter ...

  9. H3C 调试OSPF

  10. js实现小数点四舍五入

    js实现小数点四舍五入 其实这个问题,在之前的面试中被提问到了,由于笔者平时都是用原生的toFixed()的方法来保留小数点,所以当时并没有回答出来这个问题,呜呜呜~.~