Data Structure[1]
algorithm[15] 22527 Brine
我是誰
22527 鄭竣陽
Brine
BrineTW#7355
你是不是忘記我是誰了ㄏㄏ
Index
小約定(1)
- 今天的課程將以「左閉右開」來表示區間
- 程式碼中的 \(l, r\) 代表的是 \([l, r)\) 這段區間
- 也就是說,對於 \(a_l, a_r\) 間的最小值 \(a_i\),\(l \le i < r\)
- 為什麼這樣寫?
- 看了就知道了,比較舒服
小約定(2)
- 上課請多提問,提問有助於學習
而且我很久沒講課可能講錯我上課大家都不回我我很寂寞
Sparse Table
稀疏表
暖身
- 區間極值詢問
- 給定一個長度為 \(n\) 的數列 \(\langle a_k \rangle_{k = 1}^n = \langle a_1, a_2, a_3,..., a_n \rangle\)
- 有 \(q\) 次詢問,每次有一個數對 \((l, r)\)
- 對每次詢問回答 \(a_l \sim a_r\) 的最大值
- 資料範圍
- \(n \in [1, 10^5]\)
- \(q \in [1, 10^5]\)
- \(l, r \in [1, n]\)
- \(l \le r\)
- 問了就是砸線段樹
- 那如果 \(q\) 再大一點呢?
真的要線段樹嗎
- 區間極值詢問
- 給定一個長度為 \(n\) 的數列 \(\langle a_k \rangle_{k = 1}^n = \langle a_1, a_2, a_3,..., a_n \rangle\)
- 有 \(q\) 次詢問,每次有一個數對 \((l, r)\)
- 對每次詢問回答 \(a_l \sim a_r\) 的最大值
- 資料範圍
- \(n \in [1, 10^5]\)
- \(q \in [1, 2 \times 10^7]\)
- \(l, r \in [1, n]\)
- \(l \le r\)
- 真的要線段樹嗎
- 不一定不會過,但有必要嗎?
新的資料結構
- 我們希望有一個函數 \(f(i, p) = \displaystyle \max_{k \in [i, i + 2^p)} a_k \)
- \([i, i+ 2^p)\) 共有 \(2^p\) 項
- 白話一點,我們希望能快速求得 \(a_i \sim a_{i + 2^p - 1}\) 的最大值
- 有了這個可以做什麼?
用兩段得出任意長度
用兩段得出任意長度
0
1
2
3
4
5
6
7
8
9
用兩段得出任意長度
0
1
2
3
4
5
6
7
8
9
[0,3)
用兩段得出任意長度
0
1
2
3
4
5
6
7
8
9
[0,3)
用兩段得出任意長度
0
1
2
3
4
5
6
7
8
9
[3, 6)
用兩段得出任意長度
0
1
2
3
4
5
6
7
8
9
[3, 6)
用兩段得出任意長度
0
1
2
3
4
5
6
7
8
9
[2, 8)
用兩段得出任意長度
0
1
2
3
4
5
6
7
8
9
[2, 8)
用兩段得出任意長度
0
1
2
3
4
5
6
7
8
9
[2, 3)
用兩段得出任意長度
0
1
2
3
4
5
6
7
8
9
[2, 3)
用兩段得出任意長度
0
1
2
3
4
5
6
7
8
9
[0, 9)
用兩段得出任意長度
0
1
2
3
4
5
6
7
8
9
[0, 9)
用兩段得出任意長度
0
1
2
3
4
5
6
7
8
9
- 任意一段區間中的最大值都可以由兩條紅色線內的最大值求出
- 只要能把詢問紅色線的速度提升就可以有好的複雜度!
- 速度要多快?
- \(\mathcal O(1)\) 好了
如何建表
- 我們想要能夠 \(\mathcal O(1)\) 查詢,但建表可以慢慢來
- 聰明如你會發現:
- 長度為 \(2^{p + 1}\) 的區間可由兩個長度為 \(2^{p}\) 的區間得出
- \(f(i, p + 1) = \max(f(i, p), f(i + 2^p, p))\)
- 這種作法每次會得到一個兩倍長的區間
- 我們稱其為倍增法(binary lifting)
- 從小做到大,用前面的結果算後面的
查詢與複雜度
- 如何查詢?
- 假設查詢區間為 \([l, r)\)
- 令 \(d = \lfloor \log_2(r - l) \rfloor\)(中間元素的個數取 \(\log\))
- 最大值 \(=\max(區間前\ d\ 個之 \max, 區間後\ d\ 個之 \max)\)
- 即 \(\displaystyle \max_{i \in [l, r)} a_i = \max(f(l, d), f(r - 2^d, d))\)
- 複雜度
- 建表:每層 \(\mathcal O(n)\) 個元素,\(\mathcal O(\log n)\) 層,總共 \(\mathcal O(n \log n)\)
- 查詢:動作數量是常數,\(\mathcal O(1)\)
- 總複雜度 \(\mathcal O(n \log n + q)\)
Sparse Table Code
struct SparseTable {
vector< vector<int> > v;
SparseTable(int N): v(__lg(N) + 1, vector<int>(N)) {
for (auto& n: v[0]) cin >> n;
for (int i = 0, p = 1; i < __lg(N); i++, p <<= 1) {
for (int j = 0; j + p < N; j++) {
v[i + 1][j] = max(v[i][j], v[i][j + p]);
}
}
}
int query(int l, int r) {
int d = __lg(r - l);
return max(v[d][l], v[d][r - (1 << d)]);
}
};
題目
Segment Tree
線段樹
複習一下
- 線段樹是什麼
- 可以做到「點修改」、「區間查詢」之資料結構
- 修改和查詢的時間複雜度皆為 \(\mathcal O(\log n)\)
- 基本的修改能做到「加值」、「指定值」等
- 查詢能夠做到「極值查詢」、「總和查詢」等
- 可以做到「點修改」、「區間查詢」之資料結構
- 作法呢?
- 存的方法有「陣列式」和「指標式」
- 陣列式的操作可以用「遞迴式」或「迭代式」進行
- 之前的課程以陣列式儲存,遞迴式操作為主
- 本日除了遞迴式還會稍微介紹一下迭代式
線段樹模擬器
- 遞迴式
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
0
[5, 6)
13
0
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
0
[4, 6)
6
0
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
0
[0, 8)
1
0
線段樹模擬器
- 遞迴式
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
0
[5, 6)
13
0
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
0
[4, 6)
6
0
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
0
[0, 8)
1
0
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
9
[0, 8)
1
33
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
9
[0, 8)
1
33
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
9
[0, 8)
1
33
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
9
[0, 8)
1
33
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
9
[0, 8)
1
33
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
9
[0, 8)
1
33
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
9
[0, 8)
1
33
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
9
[0, 8)
1
33
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
20
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
9
[0, 8)
1
33
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
20
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
22
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
9
[0, 8)
1
33
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
20
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
22
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
27
[0, 8)
1
33
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
20
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
22
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
27
[0, 8)
1
51
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
20
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
22
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
27
[0, 8)
1
51
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
20
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
22
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
27
[0, 8)
1
51
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
20
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
22
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
27
[0, 8)
1
51
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
20
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
22
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
27
[0, 8)
1
51
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
20
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
22
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
27
[0, 8)
1
51
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
20
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
22
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
27
[0, 8)
1
51
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
20
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
22
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
27
[0, 8)
1
51
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
20
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
22
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
27
[0, 8)
1
51
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
20
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
22
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
27
[0, 8)
1
51
線段樹模擬器
- 遞迴式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
20
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
22
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
27
[0, 8)
1
51
Recursive Segment Tree
- \(\mathcal O(n)\) 初始化
#define lc(i) (i << 1)
#define rc(i) (i << 1 ^ 1)
typedef long long ll;
struct SegmentTree {
vector<ll> v;
SegmentTree(int N): v(4 << __lg(N)) {
int L = 2 << __lg(N);
for (int i = L; i < L + N; i++) cin >> v[i];
for (int i = L - 1; i > 0; i--) {
v[i] = v[lc(i)] + v[rc(i)];
}
}
void modify(int mi, ll d, int l, int r, int i = 1) {
if (mi <= l && r <= mi) {
v[i] += d;
return;
}
int m = l + r >> 1;
if (mi < m) modify(mi, d, l, m, lc(i));
if (m < mi) modify(mi, d, m, r, rc(i));
v[i] = v[lc(i)] + v[rc(i)];
}
ll query(int ql, int qr, int l, int r, int i = 1) {
if (ql <= l && r <= qr) return v[i];
int m = l + r >> 1;
ll ans = 0;
if (ql < m) ans += query(ql, qr, l, m, lc(i));
if (m < qr) ans += query(ql, qr, m, r, rc(i));
return ans;
}
};
線段樹模擬器
- 迭代式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
8
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
9
[0, 8)
1
33
線段樹模擬器
- 迭代式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
2
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
15
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
24
[4, 8)
3
9
[0, 8)
1
33
線段樹模擬器
- 迭代式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
2
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
9
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
18
[4, 8)
3
9
[0, 8)
1
33
線段樹模擬器
- 迭代式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
2
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
9
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
18
[4, 8)
3
9
[0, 8)
1
27
線段樹模擬器
- 迭代式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
2
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
9
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
18
[4, 8)
3
9
[0, 8)
1
27
線段樹模擬器
- 迭代式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
2
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
9
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
18
[4, 8)
3
9
[0, 8)
1
27
線段樹模擬器
- 迭代式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
2
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
9
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
18
[4, 8)
3
9
[0, 8)
1
27
線段樹模擬器
- 迭代式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
2
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
9
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
18
[4, 8)
3
9
[0, 8)
1
27
線段樹模擬器
- 迭代式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
2
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
9
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
18
[4, 8)
3
9
[0, 8)
1
27
線段樹模擬器
- 迭代式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
2
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
9
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
18
[4, 8)
3
9
[0, 8)
1
27
線段樹模擬器
- 迭代式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
2
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
9
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
18
[4, 8)
3
9
[0, 8)
1
27
線段樹模擬器
- 迭代式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
2
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
9
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
18
[4, 8)
3
9
[0, 8)
1
27
線段樹模擬器
- 迭代式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
2
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
9
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
18
[4, 8)
3
9
[0, 8)
1
27
線段樹模擬器
- 迭代式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
2
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
9
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
18
[4, 8)
3
9
[0, 8)
1
27
線段樹模擬器
- 迭代式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
2
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
9
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
18
[4, 8)
3
9
[0, 8)
1
27
線段樹模擬器
- 迭代式
[0, 1)
8
2
[1, 2)
9
7
[2, 3)
10
2
[3, 4)
11
7
[4, 5)
12
2
[5, 6)
13
2
[6, 7)
14
5
[7, 8)
15
0
[0, 2)
4
9
[2, 4)
5
9
[4, 6)
6
4
[6, 8)
7
5
[0, 4)
2
18
[4, 8)
3
9
[0, 8)
1
27
Iterative Segment Tree
- 快,很快,非常快
#define lc(i) (i<<1)
#define rc(i) (i<<1^1)
typedef long long ll;
struct SegmentTree {
int L;
vector<ll> v;
SegmentTree(int N): L(N), v(L << 1) {
for (int i = N; i < (N << 1); i++) cin >> v[i];
for (int i = N - 1; i > 0; i--) {
v[i] = v[lc(i)] + v[rc(i)];
}
}
void modify(int i, ll d) {
for (i += L; i; i >>= 1) v[i] += d;
}
ll query(int l, int r) {
ll sum = 0;
for (l += L, r += L; l < r; l >>= 1, r >>= 1) {
if (l & 1) sum += v[l++];
if (r & 1) sum += v[--r];
}
return sum;
}
};
等等,為什麼
- 仔細看會發現,迭代式線段樹只要開到 \(2n\) 的空間?
- 為什麼這是好的?
- 這樣會變成很多棵小的完美二元樹,詳細證明我不會
- reference
- 如果覺得很怪就還是開 \(4n\) 或 \(4 \times 2^{\lfloor \log_2 n \rfloor}\)
線段樹暖身題
Lazy Propagation
懶標
區間操作與區間和
- 用我們學到的東西,區間修改與區間求和貌似無法同時做出來?
- 點修改與區間和:BIT / 線段樹
- 區間修改與點值:(BIT / 線段樹)+ 差分 & 前綴和
點修改與點值:那個叫陣列
- 有可能做到區間修改與區間和同時嗎?
- 可以,用兩個 BIT 來維護!
- reference
- 但 BIT 很難做區間極值
- 有沒有有更一般化的方法?
- 修改的時候別那麼急,懶懶的慢慢來!
區間修改
- 先想像一下,要怎麼做區間修改
- 跟查詢類似的方法
- 發現當前節點之 \(l, r\) 在要修改的區間 \(L, R\) 中就修改
- 這會有什麼問題?
- \((L, R) = (0, n)\) 的時要修改 \(\mathcal O(n \log n)\) 個節點,爛透了
- 不如這樣,有必要改的再改
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
0
[5, 6)
13
0
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
0
[4, 6)
6
0
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
0
[0, 8)
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
0
[5, 6)
13
0
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
0
[4, 6)
6
0
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
0
[0, 8)
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
0
[5, 6)
13
0
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
0
[4, 6)
6
0
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
0
[0, 8)
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
0
[5, 6)
13
0
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
0
[4, 6)
6
0
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
0
[0, 8)
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
0
[5, 6)
13
0
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
0
[4, 6)
6
0
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
0
[0, 8)
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
0
[5, 6)
13
0
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
0
[4, 6)
6
0
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
0
[0, 8)
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
0
[5, 6)
13
0
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
0
[4, 6)
6
8
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
0
[0, 8)
1
0
0
0
0
0
0
0
0
0
0
0
0
4
0
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
0
[5, 6)
13
0
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
0
[4, 6)
6
8
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
8
[0, 8)
1
0
0
0
0
0
0
0
0
0
0
0
0
4
0
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
0
[5, 6)
13
0
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
0
[4, 6)
6
8
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
8
[0, 8)
1
8
0
0
0
0
0
0
0
0
0
0
0
4
0
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
0
[5, 6)
13
0
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
0
[4, 6)
6
8
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
8
[0, 8)
1
8
0
0
0
0
0
0
0
0
0
0
0
4
0
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
0
[5, 6)
13
0
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
0
[4, 6)
6
8
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
8
[0, 8)
1
8
0
0
0
0
0
0
0
0
0
0
0
4
0
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
0
[5, 6)
13
0
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
0
[4, 6)
6
8
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
8
[0, 8)
1
8
0
0
0
0
0
0
0
0
0
0
0
4
0
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
0
[5, 6)
13
0
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
0
[4, 6)
6
8
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
8
[0, 8)
1
8
0
0
0
0
0
0
0
0
0
0
0
4
0
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
0
[5, 6)
13
0
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
0
[4, 6)
6
8
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
8
[0, 8)
1
8
0
0
0
0
0
0
0
0
0
0
0
4
0
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
0
[5, 6)
13
0
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
6
[4, 6)
6
8
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
8
[0, 8)
1
8
0
0
0
0
0
0
0
0
0
0
0
4
3
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
0
[5, 6)
13
0
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
6
[4, 6)
6
8
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
8
[0, 8)
1
8
0
0
0
0
0
0
0
0
0
0
0
4
3
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
4
[5, 6)
13
4
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
6
[4, 6)
6
8
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
8
[0, 8)
1
8
0
0
0
0
0
4
4
0
0
0
0
0
3
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
7
[5, 6)
13
4
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
6
[4, 6)
6
8
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
8
[0, 8)
1
8
0
0
0
0
0
4
7
0
0
0
0
0
3
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
7
[5, 6)
13
4
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
6
[4, 6)
6
11
[6, 8)
7
0
[0, 4)
2
0
[4, 8)
3
8
[0, 8)
1
8
0
0
0
0
0
4
7
0
0
0
0
0
3
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
7
[5, 6)
13
4
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
6
[4, 6)
6
11
[6, 8)
7
0
[0, 4)
2
6
[4, 8)
3
11
[0, 8)
1
8
0
0
0
0
0
4
7
0
0
0
0
0
3
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
7
[5, 6)
13
4
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
6
[4, 6)
6
11
[6, 8)
7
0
[0, 4)
2
6
[4, 8)
3
11
[0, 8)
1
19
0
0
0
0
0
4
7
0
0
0
0
0
3
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
7
[5, 6)
13
4
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
6
[4, 6)
6
11
[6, 8)
7
0
[0, 4)
2
6
[4, 8)
3
11
[0, 8)
1
19
0
0
0
0
0
4
7
0
0
0
0
0
3
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
7
[5, 6)
13
4
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
6
[4, 6)
6
11
[6, 8)
7
0
[0, 4)
2
6
[4, 8)
3
11
[0, 8)
1
19
0
0
0
0
0
4
7
0
0
0
0
0
3
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
7
[5, 6)
13
4
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
6
[4, 6)
6
11
[6, 8)
7
0
[0, 4)
2
6
[4, 8)
3
11
[0, 8)
1
19
0
0
0
0
0
4
7
0
0
0
0
0
3
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
7
[5, 6)
13
4
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
6
[4, 6)
6
11
[6, 8)
7
0
[0, 4)
2
6
[4, 8)
3
11
[0, 8)
1
19
0
0
0
0
0
4
7
0
0
0
0
0
3
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
7
[5, 6)
13
4
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
6
[4, 6)
6
11
[6, 8)
7
0
[0, 4)
2
6
[4, 8)
3
11
[0, 8)
1
19
0
0
0
0
0
4
7
0
0
0
0
0
3
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
0
[3, 4)
11
0
[4, 5)
12
7
[5, 6)
13
4
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
6
[4, 6)
6
11
[6, 8)
7
0
[0, 4)
2
6
[4, 8)
3
11
[0, 8)
1
19
0
0
0
0
0
4
7
0
0
0
0
0
3
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
3
[3, 4)
11
3
[4, 5)
12
7
[5, 6)
13
4
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
6
[4, 6)
6
11
[6, 8)
7
0
[0, 4)
2
6
[4, 8)
3
11
[0, 8)
1
19
0
0
0
0
0
4
7
3
3
0
0
0
0
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
3
[3, 4)
11
3
[4, 5)
12
7
[5, 6)
13
4
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
6
[4, 6)
6
11
[6, 8)
7
0
[0, 4)
2
6
[4, 8)
3
11
[0, 8)
1
19
0
0
0
0
0
4
7
3
3
0
0
0
0
0
0
懶標模擬器
- 遞迴式
- 藍色的是尚未往下傳的更新標記
[0, 1)
8
0
[1, 2)
9
0
[2, 3)
10
3
[3, 4)
11
3
[4, 5)
12
7
[5, 6)
13
4
[6, 7)
14
0
[7, 8)
15
0
[0, 2)
4
0
[2, 4)
5
6
[4, 6)
6
11
[6, 8)
7
0
[0, 4)
2
6
[4, 8)
3
11
[0, 8)
1
19
0
0
0
0
0
4
7
3
3
0
0
0
0
0
0
Recursive Code
#define lc(i) (i << 1)
#define rc(i) (i << 1 ^ 1)
using namespace std;
typedef long long ll;
struct SegmentTree {
int L;
vector<ll> v, tag;
SegmentTree(int N): L(2 << __lg(N)), v(L << 1), tag(L << 1) {
for (int i = L; i < L + N; i++) cin >> v[i];
for (int i = L - 1; i > 0; i--) {
v[i] = v[lc(i)] + v[rc(i)];
}
}
void push(int l, int r, int i) {
int m = l + r >> 1;
tag[lc(i)] += tag[i];
tag[rc(i)] += tag[i];
v[lc(i)] += (m - l) * tag[i];
v[rc(i)] += (r - m) * tag[i];
tag[i] = 0;
}
void pull(int i) {
v[i] = v[lc(i)] + v[rc(i)];
}
void modify(int ml, int mr, ll d, int l, int r, int i = 1) {
if (ml <= l && r <= mr) {
v[i] += (r - l) * d;
tag[i] += d;
return;
}
int m = l + r >> 1;
push(l, r, i);
if (ml < m) modify(ml, mr, d, l, m, lc(i));
if (m < mr) modify(ml, mr, d, m, r, rc(i));
pull(i);
}
ll query(int ql, int qr, int l, int r, int i = 1) {
if (ql <= l && r <= qr) return v[i];
int m = l + r >> 1;
ll ans = 0;
push(l, r, i);
if (ql < m) ans += query(ql, qr, l, m, lc(i));
if (m < qr) ans += query(ql, qr, m, r, rc(i));
pull(i);
return ans;
}
};
Iterative Code
#define lc(i) (i<<1)
#define rc(i) (i<<1^1)
typedef long long ll;
struct SegmentTree {
int L;
vector<ll> v, sz, tag;
SegmentTree(int N): L(N), v(L << 1), sz(L << 1, 1), tag(L << 1) {
for (int i = N; i < (N << 1); i++) cin >> v[i];
for (int i = N - 1; i > 0; i--) {
v[i] = v[lc(i)] + v[rc(i)];
sz[i] = sz[lc(i)] + sz[rc(i)];
}
}
void update(int i, ll d) {
v[i] += d * sz[i];
tag[i] += d;
}
void pull(int i) {
for (int h = __lg(L) + 1; h; h--) {
int p = i >> h;
if (tag[p]) {
update(lc(p), tag[p]);
update(rc(p), tag[p]);
tag[p] = 0;
}
}
}
void push(int i) {
for (i >>= 1; i; i >>= 1) {
v[i] = v[lc(i)] + v[rc(i)] + tag[i] * sz[i];
}
}
void modify(int l, int r, ll d) {
int ll = l + L, rr = r + L - 1;
pull(ll), pull(rr);
for (l += L, r += L; l < r; l >>= 1, r >>= 1) {
if (l & 1) update(l++, d);
if (r & 1) update(--r, d);
}
push(ll), push(rr);
}
ll query(int l, int r) {
ll sum = 0;
pull(l + L), pull(r + L - 1);
for (l += L, r += L; l < r; l >>= 1, r >>= 1) {
if (l & 1) sum += v[l++];
if (r & 1) sum += v[--r];
}
return sum;
}
};
例題
沒了