zoukankan      html  css  js  c++  java
  • [知识点]数列分块入门1-9

    一、前言

      对线段树还挺熟悉的我之前却从没写过分块的题(?)。然后兴致一来就决定搜点练习,找到了来自hzwer的《数列分块入门1-9》,觉得挺不错的,于是决定做做。

    二、概念 / 作用

      概念:将数列等分为若干个不相交的区间,每一个区间称为一个块。

      作用:优化算法,降低复杂度。具体如何降低,在下面的题目中会逐步提及。题目呈难度递增趋势。

    三、题目 / 代码

    1、分块入门1(传送门:https://loj.ac/problem/6277

      题面:给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,单点查询。

      挺多数据结构均能实现的经典题目,譬如线段树。这里我们用分块来做。将 n 个元素等分为若干块,比如{1, 4, 8, 2, 9, 6, 3, 7, 5},等分为3块,则第一块包含的数据为{1, 4, 8},第二、三块以此类推。我们给每一个块增加一个加法标记,对于每次的区间[l, r]加法操作,直接对块进行标记叠加。

      l, r必然不一定是块的边界,也就意味着左右端点可能在块的中间,直接一个个暴力增加。设块的元素个数为m,标记块个数至多n / m个,暴力增加元素个数至多2m个,复杂度分析:O(n / m) + O(m),根据均值不等式,可证明m = √n时存在最低复杂度。故我们以下所有分块大小均默认为√n。

      询问就很轻松了,直接返回元素的值加上所在区间的标记。

    代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define MAXN 50005
     5 
     6 int n, a[MAXN], x, b[MAXN], f[MAXN];
     7 
     8 void add(int l, int r, int w) {
     9     for (int i = l; i <= min(b[l] * x, r); i++) a[i] += w;
    10     if (b[l] != b[r])
    11         for (int i = (b[r] - 1) * x + 1; i <= r; i++) a[i] += w;
    12     for (int i = b[l] + 1; i <= b[r] - 1; i++) f[i] += w;
    13 }
    14 
    15 int main() {
    16     int o, l, r, w;
    17     scanf("%d", &n), x = sqrt(n);
    18     for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    19     for (int i = 1; i <= n; i++) b[i] = (i - 1) / x + 1;
    20     for (int i = 1; i <= n; i++) {
    21         scanf("%d %d %d %d", &o, &l, &r, &w);
    22         if (o) printf("%d
    ", a[r] + f[b[r]]);
    23         else add(l, r, w);
    24     }
    25     return 0;
    26 } 

    2、分块入门2(传送门:https://loj.ac/problem/6278

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

      // 对于题目本身的分析就不多赘述了,因为hzwer已经分析的太好了,不在关公们面前耍刀了,所以需要具体的做题思路可转至hzwer的博客(见上)。

      hzwer原代码使用了vector,正好去了解了下vector(https://www.cnblogs.com/jinkun113/p/10691919.html)。当然此题不用vector问题也不大,这里把两个版本都贴出来了。

      不论是用普通数组还是vector,有一个需要注意的点是,对于每次的区间修改,左右端点所在的块会因修改而不再呈升序排列,所以需要重新维护。

    代码 - 普通版:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define MAXN 50005
     5 
     6 int n, x;
     7 int a[MAXN], b[MAXN], f[MAXN], c[505][505];
     8 
     9 void reset(int o) {
    10     memset(c[o], 0, sizeof(c[o]));
    11     for (int i = (o - 1) * x + 1; i <= min(o * x, n); i++) 
    12         c[o][++c[o][0]] = a[i];
    13     sort(c[o] + 1, c[o] + c[o][0] + 1);
    14 }
    15 
    16 void add(int l, int r, int w) {
    17     for (int i = l; i <= min(b[l] * x, r); i++) a[i] += w;
    18     reset(b[l]);
    19     if (b[l] != b[r]) {
    20         for (int i = (b[r] - 1) * x + 1; i <= r; i++) a[i] += w;
    21         reset(b[r]);
    22     }
    23     for (int i = b[l] + 1; i <= b[r] - 1; i++) f[i] += w;
    24 }
    25 
    26 int query(int l, int r, int w) {
    27     int ans = 0;
    28     for (int i = l; i <= min(b[l] * x, r); i++)
    29         if (a[i] + f[b[l]] < w) ans++;
    30     if (b[l] != b[r])
    31         for (int i = (b[r] - 1) * x + 1; i <= r; i++)
    32             if (a[i] + f[b[r]] < w) ans++;
    33     for (int i = b[l] + 1; i <= b[r] - 1; i++) {
    34         int x = w - f[i];
    35         for (int j = 1; j <= c[i][0]; j++)
    36             if (c[i][j] < x) ans++;
    37             else break;
    38     }
    39     return ans;
    40 }
    41 
    42 int main() {
    43     int o, l, r, w;
    44     scanf("%d", &n), x = sqrt(n);
    45     for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    46     for (int i = 1; i <= n; i++)
    47         b[i] = (i - 1) / x + 1, c[b[i]][++c[b[i]][0]] = a[i];
    48     for (int i = 1; i <= b[n]; i++) sort(c[i] + 1, c[i] + c[i][0] + 1);
    49     for (int i = 1; i <= n; i++) {
    50         scanf("%d %d %d %d", &o, &l, &r, &w);
    51         if (!o) add(l, r, w);
    52         else printf("%d
    ", query(l, r, w * w));
    53     }
    54     return 0;
    55 }

    代码 - vector版:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define MAXN 50005
     5 
     6 int n, x;
     7 int a[MAXN], b[MAXN], f[MAXN];
     8 
     9 vector <int> v[505];
    10 
    11 void reset(int o) {
    12     v[o].clear();
    13     for (int i = (o - 1) * x + 1; i <= min(o * x, n); i++) v[o].push_back(a[i]);
    14     sort(v[o].begin(), v[o].end());
    15 }
    16 
    17 void add(int l, int r, int w) {
    18     for (int i = l; i <= min(b[l] * x, r); i++) a[i] += w;
    19     reset(b[l]);
    20     if (b[l] != b[r]) {
    21         for (int i = (b[r] - 1) * x + 1; i <= r; i++) a[i] += w;
    22         reset(b[r]);
    23     }
    24     for (int i = b[l] + 1; i <= b[r] - 1; i++) f[i] += w;
    25 }
    26 
    27 int query(int l, int r, int w) {
    28     int ans = 0;
    29     for (int i = l; i <= min(b[l] * x, r); i++)
    30         if (a[i] + f[b[l]] < w) ans++;
    31     if (b[l] != b[r])
    32         for (int i = (b[r] - 1) * x + 1; i <= r; i++)
    33             if (a[i] + f[b[r]] < w) ans++;
    34     for (int i = b[l] + 1; i <= b[r] - 1; i++) {
    35         int x = w - f[i];
    36         ans += lower_bound(v[i].begin(), v[i].end(), x) - v[i].begin();
    37     }
    38     return ans;
    39 }
    40 
    41 int main() {
    42     int o, l, r, w;
    43     scanf("%d", &n), x = sqrt(n);
    44     for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    45     for (int i = 1; i <= n; i++)
    46         b[i] = (i - 1) / x + 1, v[b[i]].push_back(a[i]);
    47     for (int i = 1; i <= b[n]; i++) sort(v[i].begin(), v[i].end());
    48     for (int i = 1; i <= n; i++) {
    49         scanf("%d %d %d %d", &o, &l, &r, &w);
    50         if (!o) add(l, r, w);
    51         else printf("%d
    ", query(l, r, w * w));
    52     }
    53     return 0;
    54 }

    To be continued...

  • 相关阅读:
    JS 中 原生方法 (四) --- Object
    在 JavaScript 中 prototype 和 __proto__ 有什么区别
    VueJs 源码分析 ---(一) 整体对 vuejs 框架的理解
    Node.js API 初解读(三)
    npm 包的 发布 流程
    JS 中 原生方法 (三) --- Date 日期
    JS 中 原生方法 (二) --- 数组 (修---添加ES6新增)
    Mac 下VIM配置
    css预处理器(sass)
    BFC 神奇背后的原理
  • 原文地址:https://www.cnblogs.com/jinkun113/p/10692560.html
Copyright © 2011-2022 走看看