分块学习总结
Posted ywjblog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分块学习总结相关的知识,希望对你有一定的参考价值。
分块,是一种可以说是,相当,暴力的数据结构。
分块算法的思想是通过适当的划分,预处理一部分信息保存下来,用空间换取时间,达到时空平衡。
基本操作是,将一段序列,分成一定数量的块,每一块有一个长度,表示一段区间。对于区间操作,通过对完整块的整体操作和对不完整块的暴力操作而使复杂度尽可能的低
一般来讲,块的大小常设为sqrt(n),但实际上块的大小可以任意自定,不过肯定是要让复杂度尽可能的优秀
分块的效率要低于树状数组和线段树,且代码实现比较随意,相对来说更好理解。
但是俗话说的好:越简单的东西,就意味着它越牢固,可拓展性越强。
分块与其说是数据结构,它更像是一种思想,就像分治这样,虽然分块的整体框架也基本固定。
分块与树状数组,线段树相比,我个人认为,它最大的优点在于,它本身极为强大的可拓展性。
也就是说分块可以容纳相当多的区间操作,这也是由分块本身的性质决定的。
分块更多的像是一个思想。
分块实现的基本框架:
划分块,预处理,操作或查询。
操作或查询通常为4步:
1.判断要操作或是查询的区间是否在一个块内
2.若在一个块内,暴力操作或查询
3.若不在一个块内,将除了最左边和最右边这两个块外其余的块进行整体的操作,即直接对块打上修改标记之类的
4.单独暴力处理最左边的块和最右边的块
同时分块的块内还可以使用别的数据结构或是操作以实现要求或进一步优化复杂度
分块例题1—9(loj)当然更建议直接看黄学长的博客
分块入门1:
给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,单点查值。
1 #include<bits/stdc++.h>
2 using namespace std;
3 const int maxn = 50086;
4 int a[maxn], n;
5 int add[maxn];
6 int pos[maxn];//, sum[maxn];
7 int L[maxn], R[maxn];
8
9 inline int read() {
10 int x = 0, y = 1;
11 char ch = getchar();
12 while(!isdigit(ch)) {
13 if(ch == ‘-‘) y = -1;
14 ch = getchar();
15 }
16 while(isdigit(ch)) {
17 x = (x << 1) + (x << 3) + ch - ‘0‘;
18 ch = getchar();
19 }
20 return x * y;
21 }
22
23 inline void change(int l, int r, int d) {
24 int p = pos[l], q = pos[r];
25 if(p == q)
26 for(int i = l; i <= r; ++i) a[i] += d;
27 else {
28 for(int i = p + 1; i <= q - 1; ++i) add[i] += d;
29 for(int i = l; i <= R[p]; ++i) a[i] += d;
30 for(int i = L[q]; i <= r; ++i) a[i] += d;
31 }
32 }
33
34 int main() {
35 n = read();
36 for(int i = 1; i <= n; ++i)
37 a[i] = read();
38 int t = sqrt(n);
39 for(int i = 1; i <= t; ++i) {
40 L[i] = (i - 1) * t + 1;
41 R[i] = i * t;
42 }
43 if(R[t] < n) t++, L[t] = R[t - 1] + 1, R[t] = n;
44 for(int i = 1; i <= t; ++i)
45 for(int j = L[i]; j <= R[i]; ++j)
46 pos[j] = i;
47 for(int i = 1; i <= n; ++i) {
48 int opt, l, r, c;
49 opt = read(), l = read(), r = read(), c = read();
50 if(!opt) change(l, r, c);
51 else {
52 int q = pos[r];
53 cout << a[r] + add[q] << ‘
‘;
54 }
55 }
56 return 0;
57 }
分块入门2:
给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,询问区间内小于某个值 x 的元素个数。
1 #include<bits/stdc++.h>
2 #define ll long long
3 using namespace std;
4 const int maxn = 50005;
5 int n,blo;
6 int v[maxn], bl[maxn], atag[maxn];
7 vector<int>ve[505];
8
9 inline ll read() {
10 ll x = 0, y = 1;
11 char ch = getchar();
12 while(!isdigit(ch)) {
13 if(ch == ‘-‘) y = -1;
14 ch = getchar();
15 }
16 while(isdigit(ch)) {
17 x = (x << 1) + (x << 3) + ch - ‘0‘;
18 ch = getchar();
19 }
20 return x * y;
21 }
22
23 inline void reset(int x) {
24 ve[x].clear();
25 for(int i=(x-1)*blo+1;i<=min(x*blo,n);i++)
26 ve[x].push_back(v[i]);
27 sort(ve[x].begin(),ve[x].end());
28 }
29
30 inline void add(int a, int b, int c) {
31 for(int i = a; i <= min(bl[a] * blo, b); i++)
32 v[i] += c;
33 reset(bl[a]);
34 if(bl[a] != bl[b]) {
35 for(int i = (bl[b] - 1) * blo + 1; i <= b; i++)
36 v[i] += c;
37 reset(bl[b]);
38 }
39 for(int i =bl[a] + 1; i <= bl[b] - 1; i++)
40 atag[i] +=c;
41 }
42
43 inline int query(int a, int b, int c) {
44 int ans = 0;
45 for(int i = a; i <= min(bl[a] * blo, b); i++)
46 if(v[i] + atag[bl[a]] < c)ans++;
47 if(bl[a] != bl[b])
48 for(int i = (bl[b] - 1) * blo + 1; i <= b; i++)
49 if(v[i] + atag[bl[b]] < c)ans++;
50 for(int i=bl[a]+1;i<=bl[b]-1;i++) {
51 int x = c - atag[i];
52 ans += lower_bound(ve[i].begin(), ve[i].end(), x) - ve[i].begin();
53 }
54 return ans;
55 }
56
57 int main() {
58 n = read(); blo = sqrt(n);//t = sqrt(n);
59 for(int i = 1; i <= n; ++i) v[i] = read();//a[i] = read()
60 for(int i = 1; i <= n; i++) {
61 bl[i] = (i - 1) / blo + 1;//pos[i]
62 ve[bl[i]].push_back(v[i]);
63 }
64 for(int i = 1; i <= bl[n]; i++)
65 sort(ve[i].begin(), ve[i].end());
66 for(int i = 1; i <= n; i++) {
67 int opt = read(), l = read(), r = read(), d = read();
68 if(opt == 0) add(l, r, d);
69 if(opt == 1) printf("%d
", query(l, r, d * d));
70 }
71 return 0;
72 }
分块入门3:
给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,询问区间内小于某个值 x 的前驱(比其小的最大元素)。
因为要使用set(听说二分有点难卡过去),所以没写
分块入门4:
给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,区间求和
传说中的经典操作
1 #include<bits/stdc++.h>
2 #define ll long long
3 using namespace std;
4 const int maxn = 50086;
5 int n, t;
6 ll add[maxn], sum[maxn], a[maxn];
7 int L[maxn], R[maxn];
8 int pos[maxn];
9 int opt, l, r, d;
10
11 inline int read() {
12 int x = 0, y = 1;
13 char ch = getchar();
14 while(!isdigit(ch)) {
15 if(ch == ‘-‘) y = -1;
16 ch = getchar();
17 }
18 while(isdigit(ch)) {
19 x = (x << 1) + (x << 3) + ch - ‘0‘;
20 ch = getchar();
21 }
22 return x * y;
23 }
24
25 inline void change(int l, int r, int d) {
26 int p = pos[l], q = pos[r];
27 if(p == q) {
28 for(int i = l; i <= r; ++i) a[i] += d;
29 sum[p] += (r - l + 1) * d;
30 }
31 else {
32 for(int i = p + 1; i <= q - 1; ++i) add[i] += d;
33 for(int i = l; i <= R[p]; ++i) a[i] += d;
34 sum[p] += (R[p] - l + 1) * d;
35 for(int i = L[q]; i <= r; ++i) a[i] += d;
36 sum[q] += (r - L[q] + 1) * d;
37 }
38 }
39
40 inline ll ask(int l, int r, int mod) {
41 int p = pos[l], q = pos[r];
42 ll ans = 0;
43 if(p == q) {
44 for(int i = l; i <= r; ++i) ans = (ans + a[i]) % mod;
45 ans = (ans + add[p] * (r - l + 1)) % mod;
46 }
47 else {
48 for(int i = p + 1; i <= q - 1; ++i)
49 ans = (ans + sum[i] + add[i] * (R[i] - L[i] + 1)) % mod;
50 for(int i = l; i <= R[p]; ++i) ans = (ans + a[i]) % mod;
51 ans = (ans + add[p] * (R[p] - l + 1)) % mod;
52 for(int i = L[q]; i <= r; ++i) ans = (ans + a[i]) % mod;
53 ans = (ans + add[q] * (r - L[q] + 1)) % mod;
54 }
55 return ans % mod;
56 }
57
58 int main() {
59 // freopen("asd.in", "r", stdin);
60 // freopen("a.out", "w", stdout);
61 n = read(); t = sqrt(n);
62 for(int i = 1; i <= n; ++i) a[i] = read();
63 for(int i = 1; i <= t; ++i) {
64 L[i] = (i - 1) * t + 1;
65 R[i] = i * t;
66 }
67 if(R[t] < n) t++, L[t] = R[t - 1] + 1, R[t] = n;
68 for(int i = 1; i <= t; ++i)
69 for(int j = L[i]; j <= R[i]; ++j) {
70 pos[j] = i;
71 sum[i] += a[j];
72 }
73 for(int i = 1; i <= n; ++i) {
74 opt = read(), l = read(), r = read(), d = read();
75 if(!opt) change(l, r, d);
76 else cout << ask(l, r, d + 1) << ‘
‘;
77 }
78 return 0;
79 }
分块入门5:
给出一个长为 n 的数列 a1…an??,以及 n 个操作,操作涉及区间开方,区间求和。
对于区间开方,我们可以想到,对于一个区间的数,经过数次开方后,他们会变为0或1,所以采取一种分块优化的暴力做法,只要每个整块暴力开方后,记录一下元素是否都变成了 0 / 1,区间修改时跳过那些全为 0 / 1 的块即可。
1 #include<bits/stdc++.h>
2 #define ll long long
3 using namespace std;
4 const int maxn = 50086;
5 int n, a[maxn];
6 int sum[maxn], pos[maxn];
7 int L[maxn], R[maxn];
8 int t;
9 bool vis[maxn];
10 int opt, l, r, c;
11
12 inline int read() {
13 int x = 0, y = 1;
14 char ch = getchar();
15 while(!isdigit(ch)) {
16 if(ch == ‘-‘) y = -1;
17 ch = getchar();
18 }
19 while(isdigit(ch)) {
20 x = (x << 1) + (x << 3) + ch - ‘0‘;
21 ch = getchar();
22 }
23 return x * y;
24 }
25
26 inline void check_sqrt(int x) {
27 if(vis[x]) return;
28 vis[x] = 1;
29 sum[x] = 0;
30 for(int i = L[x]; i <= R[x]; ++i) {
31 a[i] = sqrt(a[i]);
32 sum[x] += a[i];
33 if(a[i] > 1) vis[x] = 0;
34 }
35 }
36
37 inline void change(int l, int r) {
38 int p = pos[l], q = pos[r];
39 if(p == q) {
40 for(int i = l; i <= r; ++i) {
41 sum[p] -= a[i];
42 a[i] = sqrt(a[i]);
43 sum[p] += a[i];
44 }
45 }
46 else {
47 for(int i = p + 1; i <= q - 1; ++i)
48 check_sqrt(i);
49 for(int i = l; i <= R[p]; ++i) {
50 sum[p] -= a[i];
51 a[i] = sqrt(a[i]);
52 sum[p] += a[i];
53 }
54 for(int i = L[q]; i <= r; ++i) {
55 sum[q] -= a[i];
56 a[i] = sqrt(a[i]);
57 sum[q] += a[i];
58 }
59 }
60 }
61
62 inline int ask(int l, int r) {
63 int ans = 0;
64 int p = pos[l], q = pos[r];
65 if(p == q) for(int i = l; i <= r; ++i) ans += a[i];
66 else {
67 for(int i = p + 1; i <= q - 1; ++i) ans += sum[i];
68 for(int i = l; i <= R[p]; ++i) ans += a[i];
69 for(int i = L[q]; i <= r; ++i) ans += a[i];
70 }
71 return ans;
72 }
73
74 int main() {
75 memset(vis, false, sizeof(vis));
76 n = read(); t = sqrt(n);
77 for(int i = 1; i <= n; ++i) a[i] = read();
78 for(int i = 1; i <= t; ++i) {
79 L[i] = (i - 1) * t + 1;
80 R[i] = i * t;
81 }
82 if(R[t] < n) t++, L[t] = R[t - 1] + 1, R[t] = n;
83 for(int i = 1; i <= t; ++i)
84 for(int j = L[i]; j <= R[i]; ++j) {
85 sum[i] += a[j];
86 pos[j] = i;
87 }
88 for(int i = 1; i <= n; ++i) {
89 opt = read(), l = read(), r = read(), c = read();
90 if(!opt) change(l, r);
91 else cout << ask(l, r) << ‘
‘;
92 }
93 return 0;
94 }
分块入门6:
给出一个长为 n 的数列,以及 n 个操作,操作涉及单点插入,单点询问,数据随机生成。
1 #include<bits/stdc++.h>
2 using namespace std;
3 const int maxn = 1e5 + 10;
4 const int maxq = 1e3 + 10;
5 struct enkidu {
6 int s, t;
7 };
8 int n, a[maxn];
9 int s[maxn << 1];
10 int k, m;
11 int opt, l, r, c;
12 vector<int> e[maxq];
13
14 inline int read() {
15 int x = 0, y = 1;
16 char ch = getchar();
17 while(!isdigit(ch)) {
18 if(ch == ‘-‘) y = -1;
19 ch = getchar();
20 }
21 while(isdigit(ch)) {
22 x = (x << 1) + (x << 3) + ch - ‘0‘;
23 ch = getchar();
24 }
25 return x * y;
26 }
27
28 inline enkidu query(int x) {
29 int i = 1;
30 while(x > (int)e[i].size())
31 x -= (int)e[i].size(), i++;
32 return (enkidu){i, x - 1};
33 }
34
35 inline void rebuild() {
36 int top = 0;
37 for(int i = 1; i <= m; ++i) {
38 int z = e[i].size();
39 for(int j = 0; j < z; ++j)
40 s[++top] = e[i][j];
41 e[i].clear();
42 }
43 k = sqrt(top), m = (top - 1) / k + 1;
44 for(int i = 1; i <= top; ++i)
45 e[(i - 1) / k + 1].push_back(s[i]);
46 }
47
48 inline void change(int l, int r) {
49 enkidu x = query(l);
50 int s = x.s, t = x.t;
51 e[s].insert(e[s].begin() + t, r);
52 if((int)e[s].size() > 20 * k)
53 rebuild();
54 }
55
56 int main() {
57 n = read();
58 for(int i = 1; i <= n; ++i) a[i] = read();
59 k = sqrt(n), m = (n - 1) / k + 1;
60 for(int i = 1; i <= n; ++i)
61 e[(i - 1) / k + 1].push_back(a[i]);
62 for(int i = 1; i <= n; ++i) {
63 opt = read(), l = read(), r = read(), c = read();
64 if(!opt) change(l, r);
65 else {
66 enkidu x = query(r);
67 int s = x.s, t = x.t;
68 cout << e[s][t] << ‘
‘;
69 }
70 }
71 return 0;
72 }
分块入门7:
给出一个长为 n 的数列,以及 n 个操作,操作涉及区间乘法,区间加法,单点询问。
比较难处理的是乘法与加法的优先级问题,对于加法,我们直接累加,对于乘法,我们在加法标记和乘法标记上都乘上要乘的数就可以保证优先级的正确性(这是很显然的)
1 #include<bits/stdc++.h>
2 #define ll long long
3 using namespace std;
4 const int maxn = 100086;
5 const int mod = 10007;
6 int n, t;
7 int a[maxn];
8 int add[maxn], mul[maxn];
9 int pos[maxn];
10 int opt, l, r, c;
11
12 inline ll read() {
13 ll x = 0, y = 1;
14 char ch = getchar();
15 while(!isdigit(ch)) {
16 if(ch == ‘-‘) y = -1;
17 ch = getchar();
18 }
19 while(isdigit(ch)) {
20 x = (x << 1) + (x << 3) + ch - ‘0‘;
21 ch = getchar();
22 }
23 return x * y;
24 }
25
26 inline void reset(int x) {
27 for(int i = (x - 1) * t + 1; i <= min(n, x * t); ++i)
28 a[i] = (a[i] * mul[x] + add[x]) % mod;
29 add[x] = 0, mul[x] = 1;
30 }
31
32 inline void change(int flag, int l, int r, int c) {
33 reset(pos[l]);
34 for(int i = l; i <= min(pos[l] * t, r); ++i) {
35 if(!flag) a[i] += c;
36 else a[i] *= c;
37 a[i] %= mod;
38 }
39 if(pos[l] != pos[r]) {
40 reset(pos[r]);
41 for(int i = (pos[r] - 1) * t + 1; i <= r; ++i) {
42 if(!flag) a[i] += c;
43 else a[i] *= c;
44 a[i] %= mod;
45 }
46 }
47 for(int i = pos[l] + 1; i <= pos[r] - 1; ++i) {
48 if(!flag) add[i] = (add[i] + c) % mod;
49 else if(flag) {
50 add[i] = add[i] * c % mod;
51 mul[i] = mul[i] * c % mod;
52 }
53 }
54 }
55
56 int main() {
57 n = read(); t = sqrt(n);
58 for(int i = 1; i <= n; ++i) a[i] = read();
59 for(int i = 1; i <= n; ++i)
60 pos[i] = (i - 1) / t + 1;
61 for(int i = 1; i <= pos[n]; ++i) mul[i] = 1;
62 for(int i = 1; i <= n; ++i) {
63 opt = read(), l = read(), r = read(), c = read();
64 if(opt == 2) cout << (a[r] * mul[pos[r]] + add[pos[r]]) % mod << ‘
‘;
65 else change(opt, l, r, c);
66 }
67 return 0;
68 }
分块入门8:
给出一个长为 n 的数列,以及 n 个操作,操作涉及区间询问等于一个数 c 的元素,并将这个区间的所有元素改为 c。
区间修改和询问操作,遇到以后建议线段树(逃)
1 #include<bits/stdc++.h>
2 using namespace std;
3 const int maxn = 100086;
4 int n, t;
5 int a[maxn];
6 int pos[maxn], tag[maxn];
7 int l, r, c;
8
9 inline int read() {
10 int x = 0, y = 1;
11 char ch = getchar();
12 while(!isdigit(ch)) {
13 if(ch == ‘-‘) y = -1;
14 ch = getchar();
15 }
16 while(isdigit(ch)) {
17 x = (x << 1) + (x << 3) + ch - ‘0‘;
18 ch = getchar();
19 }
20 return x * y;
21 }
22
23 inline void reset(int x) {
24 if(tag[x] == -1) return;
25 for(int i = (x - 1) * t + 1; i <= x * t; ++i)
26 a[i] = tag[x];
27 tag[x] = -1;
28 }
29
30 inline int sovle(int l, int r, int c) {
31 int ans = 0;
32 reset(pos[l]);
33 for(int i = l; i <= min(pos[l] * t, r); ++i) {
34 if(a[i] != c) a[i] = c;
35 else ans++;
36 }
37 if(pos[l] != pos[r]) {
38 reset(pos[r]);
39 for(int i = (pos[r] - 1) * t + 1; i <= r; ++i) {
40 if(a[i] != c) a[i] = c;
41 else ans++;
42 }
43 }
44 for(int i = pos[l] + 1; i <= pos[r] - 1; ++i) {
45 if(tag[i] != -1) {
46 if(tag[i] != c) tag[i] = c;
47 else ans += t;
48 }
49 else {
50 for(int j = (i - 1) * t + 1; j <= i * t; ++j) {
51 if(a[j] != c) a[j] = c;
52 else ans++;
53 }
54 tag[i] = c;
55 }
56 }
57 return ans;
58 }
59
60 int main() {
61 memset(tag, -1, sizeof(tag));
62 n = read(); t = sqrt(n);
63 for(int i = 1; i <= n; ++i) a[i] = read();
64 for(int i = 1; i <= n; ++i)
65 pos[i] = (i - 1) / t + 1;
66 for(int i = 1; i <= n; ++i) {
67 l = read(), r = read(), c = read();
68 cout << sovle(l, r, c) << ‘
‘;
69 }
70 return 0;
71 }
分块入门9:
给出一个长为 n 的数列,以及 n 个操作,操作涉及询问区间的最小众数。
分块最经典的区间众数操作,因为不具有区间相加性,无法使用线段树或是树状数组完成。
当然学了莫队就很简单,不会莫队(比如我),就老老实实分块吧....
首先先离散化处理一下
接着枚举预处理出任意一个区间[l, r]的众数,也就是任意一个块的左端点到其他块的右端点的众数(看了代码就懂了系列),非常显然的使用数组记录每个数出现过的次数,然后再枚举一遍,求出众数
对于每一次询问的区间[l, r],我们可以和明显的发现,大区间的众数存在于大区间内完整的块里或是左右两端不完整的块里
对于完整的块里,显然我们已经与处理过了,直接询问即可,所以我们需要快速求出不完整的块中的区间众数
然后可以发现我们上面进行了离散化,所以我们在离散时动动手脚就很好办了,对于每数,使用vector存每一次出现的位置,
然后把这个数存在的左端点和右端点二分再相减就可以求出这个数在区间里出现的次数,也就是求区间内第一个大于这个数的位置(upper_bound)和第一个小于等于这个数的位置(lower_bound)
再相减即可
剩下的直接看代码即可
1 #include<bits/stdc++.h>
2 using namespace std;
3 const int maxn = 50005;
4 int f[505][505];
5 int a[maxn], pos[maxn];
6 int val[maxn], cnt[maxn];
7 int n, l, r, t, id;
8 map<int, int> mp;
9 vector<int> v[maxn];
10
11 inline int read() {
12 int x = 0, y = 1;
13 char ch = getchar();
14 while(!isdigit(ch)) {
15 if(ch == ‘-‘) y = -1;
16 ch = getchar();
17 }
18 while(isdigit(ch)) {
19 x = (x << 1) + (x << 3) + ch - ‘0‘;
20 ch = getchar();
21 }
22 return x * y;
23 }
24
25 inline void pre(int x) {
26 memset(cnt, 0, sizeof(cnt));
27 int maxx = 0 , ans = 0;
28 for(int i = (x - 1) * t + 1; i <= n; ++i) {
29 cnt[a[i]]++;
30 int p = pos[i];
31 if(cnt[a[i]] > maxx || ((cnt[a[i]] == maxx) && val[a[i]] < val[ans]))
32 ans = a[i], maxx = cnt[a[i]];
33 f[x][p] = ans;
34 }
35 }
36
37 inline int query_cnt(int l, int r, int x) {
38 int k = upper_bound(v[x].begin(), v[x].end(), r) - lower_bound(v[x].begin(), v[x].end(), l);
39 return k;
40 }
41
42 inline int query(int l, int r) {
43 int ans, maxx = -1000000;
44 ans = f[pos[l] + 1][pos[r] - 1];
45 maxx = query_cnt(l, r, ans);
46 for(int i = l; i <= min(pos[l] * t, r); ++i) {
47 int k = query_cnt(l, r, a[i]);
48 if(k > maxx || (k == maxx && val[ans] > val[a[i]]))
49 ans = a[i], maxx = k;
50 }
51 if(pos[l] != pos[r]) {
52 for(int i = (pos[r] - 1) * t + 1; i <= r; ++i) {
53 int k = query_cnt(l, r, a[i]);
54 if(k > maxx || (k == maxx && val[ans] > val[a[i]]))
55 ans = a[i], maxx = k;
56 }
57 }
58 return ans;
59 }
60
61 int main() {
62 n = read(); t = 200;
63 for(int i = 1; i <= n; ++i) {
64 a[i] = read();
65 if(!mp[a[i]]) {
66 mp[a[i]] = ++id;
67 val[id] = a[i];
68 }
69 a[i] = mp[a[i]];
70 v[a[i]].push_back(i);
71 }
72 for(int i = 1; i <= n; ++i) pos[i] = (i - 1) / t + 1;
73 for(int i = 1; i <= pos[n]; ++i) pre(i);
74 for(int i = 1; i <= n; ++i) {
75 l = read(), r = read();
76 if(l > r) swap(l, r);
77 cout << val[query(l, r)] << ‘
‘;
78 }
79 return 0;
80 }
以上是关于分块学习总结的主要内容,如果未能解决你的问题,请参考以下文章