Skip to content

Commit f20b228

Browse files
committed
分块的简单应用
1 parent 06bc5a9 commit f20b228

File tree

2 files changed

+109
-0
lines changed

2 files changed

+109
-0
lines changed

tags/分块/Luogu_P3372.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# 洛谷线段树模板题
2+
3+
分块维护的数据结构:
4+
5+
1. `st`表示第i号块的起点
6+
7+
2. `ed`表示第i号块的终点
8+
9+
3. `mark`表示第i号块整个区间打上的更新标记
10+
11+
4. `sum`表示第i号块离散加上的数据
12+
13+
5. `size`表示第i号块的大小
14+
15+
6. `bel`表示下标对应第i号块的位置
16+
17+
分块使得每次操作时间复杂度趋向于`O(sqrt(n))`,它的想法比较简单,但是码量却不小,对于某些题目,维护信息不满足交换律,可能使用分块优于线段树等
18+
19+
```c
20+
void solve(){
21+
int n; cin >> n;
22+
vector<ll> a(n + 1);
23+
for (int i = 1; i <= n; i++) {
24+
cin >> a[i];
25+
}
26+
int sq = sqrt(n);
27+
vector<ll> st(sq + 1), ed(sq + 1), size(sq + 1), sum(sq + 1), mark(sq + 1);
28+
for (int i = 1; i <= sq; i++) {
29+
st[i] = n / sq * (i - 1) + 1;
30+
ed[i] = n / sq * i;
31+
}
32+
ed[sq] = n;
33+
for (int i = 1; i <= sq; i++) {
34+
size[i] = ed[i] - st[i];
35+
}
36+
vector<ll> bel(n + 1);
37+
for (int i = 1; i <= sq; i++) {
38+
for (int j = st[i]; j <= ed[i]; j++) {
39+
sum[i] += a[j];
40+
bel[j] = i;
41+
}
42+
}
43+
auto add = [&](int x, int y, int k){
44+
if(bel[x] == bel[y]){
45+
for (int i = x; i <= y; i++) {
46+
a[i] += k;
47+
sum[bel[i]] += k;
48+
}
49+
}
50+
else{
51+
for (int i = x; i <= ed[bel[x]]; i++) {
52+
a[i] += k;
53+
sum[bel[i]] += k;
54+
}
55+
for (int i = st[bel[y]]; i <= y; i++) {
56+
a[i] += k;
57+
sum[bel[i]] += k;
58+
}
59+
for (int i = bel[x] + 1; i < bel[y]; i++) {
60+
mark[i] += k;
61+
}
62+
}
63+
};
64+
auto query = [&](int x, int y)->ll{
65+
ll s = 0;
66+
if(bel[x] == bel[y]){
67+
for (int i = x; i <= y; i++) {
68+
s += a[i] + mark[bel[i]];
69+
}
70+
}
71+
else{
72+
for (int i = x; i <= ed[bel[x]]; i++) {
73+
s += a[i] + mark[bel[i]];
74+
}
75+
for (int i = st[bel[y]]; i <= y; i++) {
76+
s += a[i] + mark[bel[i]];
77+
}
78+
for (int i = bel[x] + 1; i < bel[y]; i++) {
79+
s += sum[i] + mark[i] * size[i];
80+
}
81+
}
82+
return s;
83+
};
84+
for (int i = 0; i < n; i++) {
85+
int op, l, r, k;
86+
cin >> op >> l >> r >> k;
87+
if(op == 0){
88+
add(l, r, k);
89+
}
90+
else{
91+
cout << query(l, r) << endl;
92+
}
93+
}
94+
}
95+
96+
```

tags/分块/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# 为什么分块?
2+
3+
**分块是一种思想,将一个整体分为若干个小块,对整块整体处理,对零碎块单独处理。**
4+
5+
分块适用于区间更新与区间查询的一些场景,尤其是某些信息,线段树与树状数组维护起来相当麻烦,或者说很难维护,此时分块就可以用上了。
6+
7+
#
8+
9+
参考来源:
10+
11+
1. https://oi-wiki.org/ds/decompose/
12+
13+
2. https://zhuanlan.zhihu.com/p/114268236

0 commit comments

Comments
 (0)