[分塊]數列分塊入門1-9

1、前言html

  對線段樹還挺熟悉的我以前卻從沒寫過度塊的題(?)。而後興致一來就決定搜點練習,找到了來自hzwer的《數列分塊入門1-9》,以爲挺不錯的,因而決定作作。c++

 

2、概念 / 做用算法

  概念:將數列等分爲若干個不相交的區間,每個區間稱爲一個塊。數組

  做用:優化算法,下降複雜度。具體如何下降,在下面的題目中會逐步說起。題目呈難度遞增趨勢。數據結構

 

3、題目 / 代碼優化

一、分塊入門1(傳送門:https://loj.ac/problem/6277spa

  題面:給出一個長爲 n 的數列,以及 n 個操做,操做涉及區間加法,單點查詢。code

  挺多數據結構均能實現的經典題目,譬如線段樹。這裏咱們用分塊來作。將 n 個元素等分爲若干塊,好比{1, 4, 8, 2, 9, 6, 3, 7, 5},等分爲3塊,則第一塊包含的數據爲{1, 4, 8},第2、三塊以此類推。咱們給每個塊增長一個加法標記,對於每次的區間[l, r]加法操做,直接對塊進行標記疊加。htm

  l, r必然不必定是塊的邊界,也就意味着左右端點可能在塊的中間,直接一個個暴力增長。設塊的元素個數爲m,標記塊個數至多n / m個,暴力增長元素個數至多2m個,複雜度分析:O(n / m) + O(m),根據均值不等式,可證實m = √n時存在最低複雜度。故咱們如下全部分塊大小均默認爲√n。blog

  詢問就很輕鬆了,直接返回元素的值加上所在區間的標記。

 

代碼:

 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\n", a[r] + f[b[r]]);
23         else add(l, r, w);
24     }
25     return 0;
26 } 

 

二、分塊入門2(傳送門:https://loj.ac/problem/6278

  題面:給出一個長爲 n 的數列,以及 n 個操做,操做涉及區間加法,詢問區間內小於某個值 x 的元素個數。

  // 對於題目自己的分析就很少贅述了,由於hzwer已經分析的太好了,不在關公們面前耍刀了,因此須要具體的作題思路可轉至hzwer的博客(見上)。

  hzwer原代碼使用了vector,正好去了解了下vector(http://www.javashuo.com/article/p-uybbyqbr-kx.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\n", 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\n", query(l, r, w * w));
52     }
53     return 0;
54 }

 

To be continued...

相關文章
相關標籤/搜索