ac-library-rb 0.5.1 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/README.ja.md +23 -0
- data/README.md +2 -0
- data/Rakefile +1 -1
- data/document_en/lazy_segtree.md +20 -4
- data/document_en/segtree.md +16 -0
- data/document_ja/lazy_segtree.md +55 -13
- data/document_ja/segtree.md +11 -3
- data/lib/ac-library-rb/version.rb +1 -1
- data/lib/lazy_segtree.rb +56 -9
- data/lib/segtree.rb +16 -10
- data/lib_lock/ac-library-rb/lazy_segtree.rb +56 -9
- data/lib_lock/ac-library-rb/segtree.rb +16 -10
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dc333b7ea588fedc3aaf0379408bb5cfa0cbe78ce78286375233e296ee687338
|
4
|
+
data.tar.gz: 8b22febe194ced2ce838d6c5c59316e813acb1d3835988981bcd8ee48512a460
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '09aae15824b338694ba75027deea63c5955e9056fb5af8ea3d382d0218fa6278ef8af2e9d281315ef45e01a4296e6b15688f221ea39ca03153a1799d7770cc7e'
|
7
|
+
data.tar.gz: db447beabc1e50f306a26a34128394e0c424d5291cb9df4b616bcadc3956a5acd90b6344fc80eaedadfa88efba96ee3918a622e582b8957c3b21be12f44b3636
|
data/.rubocop.yml
CHANGED
@@ -91,6 +91,7 @@ Naming/FileName:
|
|
91
91
|
- 'lib_lock/ac-library-rb.rb'
|
92
92
|
Naming/AccessorMethodName:
|
93
93
|
Exclude:
|
94
|
+
- 'lib/lazy_segtree.rb'
|
94
95
|
- 'lib/modint.rb'
|
95
96
|
Naming/MethodName:
|
96
97
|
Exclude:
|
@@ -124,6 +125,7 @@ Style/GlobalVars:
|
|
124
125
|
AutoCorrect: false
|
125
126
|
Exclude:
|
126
127
|
- 'lib/modint.rb'
|
128
|
+
- 'test/lazy_segtree_test.rb'
|
127
129
|
Style/FrozenStringLiteralComment:
|
128
130
|
Enabled: false
|
129
131
|
Style/InverseMethods:
|
@@ -179,6 +181,7 @@ Style/SelfAssignment:
|
|
179
181
|
Style/Semicolon:
|
180
182
|
Exclude:
|
181
183
|
- 'lib/lazy_segtree.rb'
|
184
|
+
- 'test/lazy_segtree_test.rb'
|
182
185
|
Style/SlicingWithRange:
|
183
186
|
Enabled: false
|
184
187
|
Style/SpecialGlobalVars:
|
data/README.ja.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# ac-library-rb
|
2
2
|
|
3
|
+
[](https://badge.fury.io/rb/ac-library-rb)
|
4
|
+
|
3
5
|
ac-library-rbは、AtCoder Library (ACL)のRuby版です。
|
4
6
|
|
5
7
|
ACLの詳細は、以下をご覧ください.
|
@@ -114,12 +116,33 @@ ACL本家のレポジトリ名がac-libraryとハイフン区切りで、それ
|
|
114
116
|
|
115
117
|
宣伝・バグ報告などしてもらえると嬉しいです。
|
116
118
|
|
119
|
+
## ac-library-rbを開発したい方向けの情報
|
120
|
+
|
121
|
+
### コーディングスタイル
|
122
|
+
|
123
|
+
Rubocop(Rubyのlintツール)の設定ファイル`.rubocop.yml`は、参考に置いています。
|
124
|
+
Rubocopのルールを守ることが必ずしもよくなかったり、ルールを守ることが難しかったりもするので、Rubocopの適用は必須ではないです。
|
125
|
+
|
126
|
+
推奨スタイル
|
127
|
+
- インデントは、半角スペース2文字
|
128
|
+
- 行末の余計なスペースは削除
|
129
|
+
|
130
|
+
### ディレクトリの説明
|
131
|
+
|
132
|
+
`lib`ディレクトリ内に各種のデータ構造などのライブラリがあります。
|
133
|
+
`lib_lock`は、Gem用にモジュール化させるため`lib`の内容をコピーする形でモジュール化させています。
|
134
|
+
`bin/lock_lib.rb`を実行することで、`lib`から`lib_lock`にモジュール化させる形でコピーします。
|
135
|
+
なお、`rake`コマンドでテストを実行させると、自動的に`require_relative "./bin/lock_lib.rb"`により、コピーが行われます。
|
136
|
+
このあたりはトリッキーで、予定は未定ですが、今後全てモジュール化される等に統一される可能性があります。
|
137
|
+
|
117
138
|
## その他の情報
|
118
139
|
|
119
140
|
### RubyのSlackのAtCoderチャンネル
|
120
141
|
|
121
142
|
[ruby-jp](https://ruby-jp.github.io/) に"atcoder"というチャンネルがあります。
|
122
143
|
|
144
|
+
ここで、バグ報告などすると、競プロ詳しい人などが反応しやすいかもしれません。
|
145
|
+
|
123
146
|
Slackに3000人、atcoderチャンネルに250人以上の登録者がいるので、お気軽に参加してください。
|
124
147
|
|
125
148
|
### 他言語のライブラリ
|
data/README.md
CHANGED
data/Rakefile
CHANGED
data/document_en/lazy_segtree.md
CHANGED
@@ -105,13 +105,29 @@ seg.range_apply(l, r, val)
|
|
105
105
|
|
106
106
|
- `O(log n)`
|
107
107
|
|
108
|
-
### max_right
|
108
|
+
### max_right(l){ } -> Integer
|
109
109
|
|
110
|
-
|
110
|
+
It applies binary search on the LazySegtree.
|
111
111
|
|
112
|
-
|
112
|
+
**Constraints**
|
113
|
+
|
114
|
+
- `0 ≦ l ≦ n`
|
115
|
+
|
116
|
+
**Complexity**
|
117
|
+
|
118
|
+
- `O(log n)`
|
119
|
+
|
120
|
+
### min_left(r){ } -> Integer
|
113
121
|
|
114
|
-
|
122
|
+
It applies binary search on the LazySegtree.
|
123
|
+
|
124
|
+
**Constraints**
|
125
|
+
|
126
|
+
- `0 ≦ r ≦ n`
|
127
|
+
|
128
|
+
**Complexity**
|
129
|
+
|
130
|
+
- `O(log n)`
|
115
131
|
|
116
132
|
## Verified
|
117
133
|
|
data/document_en/segtree.md
CHANGED
@@ -104,6 +104,14 @@ It returns `op(a[0], ..., a[n - 1])`.
|
|
104
104
|
seg.max_right(l, &f)
|
105
105
|
```
|
106
106
|
|
107
|
+
**Constraints**
|
108
|
+
|
109
|
+
- `0 ≦ l ≦ n`
|
110
|
+
|
111
|
+
**Complexity**
|
112
|
+
|
113
|
+
- `O(log n)`
|
114
|
+
|
107
115
|
It applies binary search on the segment tree.
|
108
116
|
|
109
117
|
### min_left(r, &f) -> Integer
|
@@ -114,6 +122,14 @@ seg.min_left(r, &f)
|
|
114
122
|
|
115
123
|
It applies binary search on the segment tree.
|
116
124
|
|
125
|
+
**Constraints**
|
126
|
+
|
127
|
+
- `0 ≦ r ≦ n`
|
128
|
+
|
129
|
+
**Complexity**
|
130
|
+
|
131
|
+
- `O(log n)`
|
132
|
+
|
117
133
|
## Verified
|
118
134
|
|
119
135
|
- [ALPC: J \- Segment Tree](https://atcoder.jp/contests/practice2/tasks/practice2_j)
|
data/document_ja/lazy_segtree.md
CHANGED
@@ -8,10 +8,10 @@
|
|
8
8
|
|
9
9
|
## 特異メソッド
|
10
10
|
|
11
|
-
### new(v, e, id
|
11
|
+
### new(v, e, id){ }
|
12
12
|
|
13
13
|
```ruby
|
14
|
-
seg = LazySegtree.new(v, e, id
|
14
|
+
seg = LazySegtree.new(v, e, id)
|
15
15
|
```
|
16
16
|
|
17
17
|
第1引数は、`Integer`または`Array`です。
|
@@ -21,8 +21,22 @@ seg = LazySegtree.new(v, e, id, op, mapping, compositon)
|
|
21
21
|
|
22
22
|
第2引数`e`は、単位元です。ブロックで二項演算`op(x, y)`を定義することで、モノイドを定義する必要があります。
|
23
23
|
|
24
|
+
また、インスタンス作成後に、`LazySegtree#set_mapping{ }`と`LazySegment#set_composition{ }`を用い、適切にインスタンス変数にprocを設定する必要があります。
|
25
|
+
|
24
26
|
**計算量** `O(n)`
|
25
27
|
|
28
|
+
### new(v, op, e, mapping, composition, id)
|
29
|
+
### new(v, e, id, op, mapping, composition)
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
seg = LazySegtree.new(v, op, e, mapping, compositon, id)
|
33
|
+
seg = LazySegtree.new(v, e, id, op, mapping, compositon)
|
34
|
+
```
|
35
|
+
|
36
|
+
前者は、本家ライブラリに合わせた引数の順番。
|
37
|
+
後者は、procを後ろにまとめた引数の順番で、これは非推奨。
|
38
|
+
内部で、第2引数がprocかどうかで、場合分けしています。
|
39
|
+
|
26
40
|
## インスタンスメソッド
|
27
41
|
|
28
42
|
### set(pos, x)
|
@@ -53,7 +67,7 @@ seg.get(pos)
|
|
53
67
|
seg.prod(l, r)
|
54
68
|
```
|
55
69
|
|
56
|
-
`op(a[l], ..., a[r - 1])`
|
70
|
+
`op(a[l], ..., a[r - 1])` を返します。引数は半開区間です。`l == r`のとき、単位元`e`を返します。
|
57
71
|
|
58
72
|
**制約** `0 ≦ l ≦ r ≦ n`
|
59
73
|
|
@@ -65,19 +79,24 @@ seg.prod(l, r)
|
|
65
79
|
seg.all_prod
|
66
80
|
```
|
67
81
|
|
68
|
-
`op(a[0], ..., a[n - 1])`
|
82
|
+
`op(a[0], ..., a[n - 1])` を返します。サイズが0のときは、単位元`e`を返します。
|
69
83
|
|
70
84
|
**計算量** `O(1)`
|
71
85
|
|
72
86
|
### apply(pos, val)
|
87
|
+
### apply(s, r, val)
|
73
88
|
|
74
89
|
```ruby
|
75
90
|
seg.apply(pos, val)
|
91
|
+
seg.apply(l, r, val)
|
76
92
|
```
|
77
93
|
|
78
|
-
|
94
|
+
1. `a[p] = f(a[p])`
|
95
|
+
2. 半開区間`i = l..r`について`a[i] = f(a[i])`
|
79
96
|
|
80
|
-
**制約**
|
97
|
+
**制約**
|
98
|
+
1. `0 ≦ pos < n`
|
99
|
+
2. `0 ≦ l ≦ r ≦ n`
|
81
100
|
|
82
101
|
**計算量** `O(log n)`
|
83
102
|
|
@@ -87,28 +106,44 @@ seg.apply(pos, val)
|
|
87
106
|
seg.range_apply(l, r, val)
|
88
107
|
```
|
89
108
|
|
109
|
+
3引数の`apply`を呼んだときに、内部で呼ばれるメソッド。
|
110
|
+
直接、`range_apply`を呼ぶこともできる。
|
111
|
+
|
90
112
|
**制約** `0 ≦ l ≦ r ≦ n`
|
91
113
|
|
92
114
|
**計算量** `O(log n)`
|
93
115
|
|
94
|
-
### max_right
|
116
|
+
### max_right(l){ } -> Integer
|
95
117
|
|
96
|
-
|
118
|
+
LazySegtree上で、二分探索をします。
|
97
119
|
|
98
|
-
|
120
|
+
**制約** `0 ≦ l ≦ n`
|
99
121
|
|
100
|
-
|
122
|
+
**計算量** `O(log n)`
|
123
|
+
|
124
|
+
### min_left(r){ } -> Integer
|
125
|
+
|
126
|
+
LazySegtree上で、二分探索をします。
|
127
|
+
|
128
|
+
**制約** `0 ≦ r ≦ n`
|
129
|
+
|
130
|
+
**計算量** `O(log n)`
|
101
131
|
|
102
132
|
## Verified
|
103
133
|
|
104
|
-
|
105
|
-
- [AIZU ONLINE JUDGE DSL\_2\_F RMQ and RUQ](http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=DSL_2_F)
|
106
|
-
- [AIZU ONLINE JUDGE DSL\_2\_G RSQ and RAQ](http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=DSL_2_G)
|
134
|
+
問題のリンクです。Verified済みです。解答はテストコードをご参考ください。
|
135
|
+
- [AIZU ONLINE JUDGE DSL\_2\_F RMQ and RUQ](ttps://onlinejudge.u-aizu.ac.jp/problems/DSL_2_F) ([旧DSL_2_F](http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=DSL_2_F))
|
136
|
+
- [AIZU ONLINE JUDGE DSL\_2\_G RSQ and RAQ](https://onlinejudge.u-aizu.ac.jp/problems/DSL_2_G) ([旧DSL_2_G](http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=DSL_2_G))
|
137
|
+
- [AIZU ONLINE JUDGE DSL\_2\_H RMQ and RAQ](https://onlinejudge.u-aizu.ac.jp/problems/DSL_2_H) ([旧DSL_2_H](http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=DSL_2_H))
|
138
|
+
- [AIZU ONLINE JUDGE DSL\_2\_I RSQ and RUQ](https://onlinejudge.u-aizu.ac.jp/problems/DSL_2_I) ([旧DSL_2_I](http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=DSL_2_I))
|
107
139
|
|
108
140
|
以下の問題は、Rubyでは実行時間が厳しくTLEになりACできてないです。
|
109
141
|
- [ALPC: K \- Range Affine Range Sum](https://atcoder.jp/contests/practice2/tasks/practice2_k)
|
110
142
|
- [ALPC: L \- Lazy Segment Tree](https://atcoder.jp/contests/practice2/tasks/practice2_l)
|
111
143
|
|
144
|
+
下記は、ジャッジにだしてないが、サンプルに正解。`max_right`, `min_left`を使う問題。
|
145
|
+
- [Quora Programming Challenge 2021: Skyscraper](https://jonathanirvin.gs/files/division2_3d16774b0423.pdf#page=5)
|
146
|
+
|
112
147
|
## 参考リンク
|
113
148
|
|
114
149
|
- 当ライブラリ
|
@@ -133,3 +168,10 @@ seg.range_apply(l, r, val)
|
|
133
168
|
### `ceil_pow2`ではなく、`bit_length`
|
134
169
|
|
135
170
|
本家C++ライブラリは独自定義の`internal::ceil_pow2`関数を用いてますが、本ライブラリではRuby既存のメソッド`Integer#bit_length`を用いています。そちらの方が計測した結果、高速でした。
|
171
|
+
|
172
|
+
## 問題点
|
173
|
+
|
174
|
+
### ミュータブルな単位元
|
175
|
+
|
176
|
+
本家ACL同様に、初期化の際に配列でも数値でもいいとなっている。
|
177
|
+
しかし、数値で要素数を指定した際に、ミュータブルなクラスでも同一オブジェクトで要素を作ってしまっている。
|
data/document_ja/segtree.md
CHANGED
@@ -66,7 +66,7 @@ seg.get(pos)
|
|
66
66
|
seg.prod(l, r)
|
67
67
|
```
|
68
68
|
|
69
|
-
`op(a[l], ..., a[r - 1])`
|
69
|
+
`op(a[l], ..., a[r - 1])` を返します。引数は半開区間です。`l == r`のとき、単位元`e`を返します。
|
70
70
|
|
71
71
|
**制約**
|
72
72
|
|
@@ -82,7 +82,7 @@ seg.prod(l, r)
|
|
82
82
|
seg.all_prod
|
83
83
|
```
|
84
84
|
|
85
|
-
`op(a[0], ..., a[n - 1])`
|
85
|
+
`op(a[0], ..., a[n - 1])` を返します。空のセグメントツリー、つまりサイズが0のとき、単位元`e`を返します。
|
86
86
|
|
87
87
|
**計算量**
|
88
88
|
|
@@ -96,6 +96,10 @@ seg.max_right(l, &f)
|
|
96
96
|
|
97
97
|
Segtree上で二分探索をします。
|
98
98
|
|
99
|
+
**制約** `0 ≦ l ≦ n`
|
100
|
+
|
101
|
+
**計算量** `O(log n)`
|
102
|
+
|
99
103
|
### min_left(r, &f) -> Integer
|
100
104
|
|
101
105
|
```ruby
|
@@ -104,11 +108,15 @@ seg.min_left(r, &f)
|
|
104
108
|
|
105
109
|
Segtree上で二分探索をします。
|
106
110
|
|
111
|
+
**制約** `0 ≦ r ≦ n`
|
112
|
+
|
113
|
+
**計算量** `O(log n)`
|
114
|
+
|
107
115
|
## Verified
|
108
116
|
|
109
117
|
- [ALPC: J \- Segment Tree](https://atcoder.jp/contests/practice2/tasks/practice2_j)
|
110
118
|
|
111
|
-
- [F \- Range Xor Query](https://atcoder.jp/contests/abc185/tasks/abc185_f)
|
119
|
+
- [ABC185: F \- Range Xor Query](https://atcoder.jp/contests/abc185/tasks/abc185_f)
|
112
120
|
- xorのセグメントツリーの基本的な典型問題です。FenwickTree(BIT)をxorに改造するだけでも解けます。
|
113
121
|
- [ACコード(1538ms)](https://atcoder.jp/contests/abc185/submissions/18746817): 通常のSegtree解。
|
114
122
|
- [ACコード(821ms)](https://atcoder.jp/contests/abc185/submissions/18769200): FenwickTree(BIT)のxor改造版。
|
data/lib/lazy_segtree.rb
CHANGED
@@ -1,17 +1,21 @@
|
|
1
1
|
# Segment tree with Lazy propagation
|
2
2
|
class LazySegtree
|
3
|
-
attr_reader
|
3
|
+
attr_reader :d, :lz, :e, :id
|
4
4
|
attr_accessor :op, :mapping, :composition
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
# new(v, op, e, mapping, composition, id)
|
7
|
+
# new(v, e, id, op, mapping, composition)
|
8
|
+
# new(v, e, id){ |x, y| }
|
9
|
+
def initialize(v, a1, a2, a3 = nil, a4 = nil, a5 = nil, &op_block)
|
10
|
+
if a1.is_a?(Proc)
|
11
|
+
@op, @e, @mapping, @composition, @id = a1, a2, a3, a4, a5
|
12
|
+
else
|
13
|
+
@e, @id, @op, @mapping, @composition = a1, a2, a3, a4, a5
|
14
|
+
@op ||= op_block
|
15
|
+
end
|
16
|
+
v = Array.new(v, @e) if v.is_a?(Integer)
|
8
17
|
|
9
18
|
@n = v.size
|
10
|
-
@e = e
|
11
|
-
@id = id
|
12
|
-
@op = op
|
13
|
-
@mapping = mapping
|
14
|
-
@composition = composition
|
15
19
|
|
16
20
|
@log = (@n - 1).bit_length
|
17
21
|
@size = 1 << @log
|
@@ -22,18 +26,28 @@ class LazySegtree
|
|
22
26
|
(@size - 1).downto(1) { |i| update(i) }
|
23
27
|
end
|
24
28
|
|
29
|
+
def set_mapping(&mapping)
|
30
|
+
@mapping = mapping
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_composition(&composition)
|
34
|
+
@composition = composition
|
35
|
+
end
|
36
|
+
|
25
37
|
def set(pos, x)
|
26
38
|
pos += @size
|
27
39
|
@log.downto(1) { |i| push(pos >> i) }
|
28
40
|
@d[pos] = x
|
29
41
|
1.upto(@log) { |i| update(pos >> i) }
|
30
42
|
end
|
43
|
+
alias []= set
|
31
44
|
|
32
45
|
def get(pos)
|
33
46
|
pos += @size
|
34
47
|
@log.downto(1) { |i| push(pos >> i) }
|
35
48
|
@d[pos]
|
36
49
|
end
|
50
|
+
alias [] get
|
37
51
|
|
38
52
|
def prod(l, r)
|
39
53
|
return @e if l == r
|
@@ -68,7 +82,11 @@ class LazySegtree
|
|
68
82
|
@d[1]
|
69
83
|
end
|
70
84
|
|
71
|
-
|
85
|
+
# apply(pos, f)
|
86
|
+
# apply(l, r, f) -> range_apply(l, r, f)
|
87
|
+
def apply(pos, f, fr = nil)
|
88
|
+
return range_apply(pos, f, fr) if fr
|
89
|
+
|
72
90
|
pos += @size
|
73
91
|
@log.downto(1) { |i| push(pos >> i) }
|
74
92
|
@d[pos] = @mapping.call(f, @d[pos])
|
@@ -132,6 +150,35 @@ class LazySegtree
|
|
132
150
|
@n
|
133
151
|
end
|
134
152
|
|
153
|
+
def min_left(r, &g)
|
154
|
+
return 0 if r == 0
|
155
|
+
|
156
|
+
r += @size
|
157
|
+
@log.downto(1) { |i| push((r - 1) >> i) }
|
158
|
+
sm = @e
|
159
|
+
|
160
|
+
loop do
|
161
|
+
r -= 1
|
162
|
+
while r > 1 && r.odd?
|
163
|
+
r /= 2
|
164
|
+
end
|
165
|
+
unless g.call(@op.call(@d[r], sm))
|
166
|
+
while r < @size
|
167
|
+
push(r)
|
168
|
+
r = r * 2 + 1
|
169
|
+
if g.call(@op.call(@d[r], sm))
|
170
|
+
sm = @op.call(@d[r], sm)
|
171
|
+
r -= 1
|
172
|
+
end
|
173
|
+
end
|
174
|
+
return r + 1 - @size
|
175
|
+
end
|
176
|
+
sm = @op.call(@d[r], sm)
|
177
|
+
break if (r & -r) == r
|
178
|
+
end
|
179
|
+
0
|
180
|
+
end
|
181
|
+
|
135
182
|
def update(k)
|
136
183
|
@d[k] = @op.call(@d[2 * k], @d[2 * k + 1])
|
137
184
|
end
|
data/lib/segtree.rb
CHANGED
@@ -2,21 +2,25 @@
|
|
2
2
|
class Segtree
|
3
3
|
attr_reader :d, :op, :n, :leaf_size, :log
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
# new(e){ |x, y| }
|
6
|
+
# new(v, e){ |x, y| }
|
7
|
+
# new(v, op, e)
|
8
|
+
def initialize(a0, a1 = nil, a2 = nil, &block)
|
9
|
+
if a1.nil?
|
10
|
+
@e, @op = a0, proc(&block)
|
11
|
+
v = []
|
12
|
+
elsif a2.nil?
|
13
|
+
@e, @op = a1, proc(&block)
|
14
|
+
v = (a0.is_a?(Array) ? a0 : [@e] * a0)
|
15
|
+
else
|
16
|
+
@op, @e = a1, a2
|
17
|
+
v = (a0.is_a?(Array) ? a0 : [@e] * a0)
|
11
18
|
end
|
12
19
|
|
13
|
-
@e = e
|
14
|
-
@op = proc(&block)
|
15
|
-
|
16
20
|
@n = v.size
|
17
21
|
@log = (@n - 1).bit_length
|
18
22
|
@leaf_size = 1 << @log
|
19
|
-
@d = Array.new(@leaf_size * 2
|
23
|
+
@d = Array.new(@leaf_size * 2, @e)
|
20
24
|
v.each_with_index { |v_i, i| @d[@leaf_size + i] = v_i }
|
21
25
|
(@leaf_size - 1).downto(1) { |i| update(i) }
|
22
26
|
end
|
@@ -26,10 +30,12 @@ class Segtree
|
|
26
30
|
@d[q] = x
|
27
31
|
1.upto(@log) { |i| update(q >> i) }
|
28
32
|
end
|
33
|
+
alias []= set
|
29
34
|
|
30
35
|
def get(pos)
|
31
36
|
@d[@leaf_size + pos]
|
32
37
|
end
|
38
|
+
alias [] get
|
33
39
|
|
34
40
|
def prod(l, r)
|
35
41
|
return @e if l == r
|
@@ -1,18 +1,22 @@
|
|
1
1
|
module AcLibraryRb
|
2
2
|
# Segment tree with Lazy propagation
|
3
3
|
class LazySegtree
|
4
|
-
attr_reader
|
4
|
+
attr_reader :d, :lz, :e, :id
|
5
5
|
attr_accessor :op, :mapping, :composition
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
# new(v, op, e, mapping, composition, id)
|
8
|
+
# new(v, e, id, op, mapping, composition)
|
9
|
+
# new(v, e, id){ |x, y| }
|
10
|
+
def initialize(v, a1, a2, a3 = nil, a4 = nil, a5 = nil, &op_block)
|
11
|
+
if a1.is_a?(Proc)
|
12
|
+
@op, @e, @mapping, @composition, @id = a1, a2, a3, a4, a5
|
13
|
+
else
|
14
|
+
@e, @id, @op, @mapping, @composition = a1, a2, a3, a4, a5
|
15
|
+
@op ||= op_block
|
16
|
+
end
|
17
|
+
v = Array.new(v, @e) if v.is_a?(Integer)
|
9
18
|
|
10
19
|
@n = v.size
|
11
|
-
@e = e
|
12
|
-
@id = id
|
13
|
-
@op = op
|
14
|
-
@mapping = mapping
|
15
|
-
@composition = composition
|
16
20
|
|
17
21
|
@log = (@n - 1).bit_length
|
18
22
|
@size = 1 << @log
|
@@ -23,18 +27,28 @@ module AcLibraryRb
|
|
23
27
|
(@size - 1).downto(1) { |i| update(i) }
|
24
28
|
end
|
25
29
|
|
30
|
+
def set_mapping(&mapping)
|
31
|
+
@mapping = mapping
|
32
|
+
end
|
33
|
+
|
34
|
+
def set_composition(&composition)
|
35
|
+
@composition = composition
|
36
|
+
end
|
37
|
+
|
26
38
|
def set(pos, x)
|
27
39
|
pos += @size
|
28
40
|
@log.downto(1) { |i| push(pos >> i) }
|
29
41
|
@d[pos] = x
|
30
42
|
1.upto(@log) { |i| update(pos >> i) }
|
31
43
|
end
|
44
|
+
alias []= set
|
32
45
|
|
33
46
|
def get(pos)
|
34
47
|
pos += @size
|
35
48
|
@log.downto(1) { |i| push(pos >> i) }
|
36
49
|
@d[pos]
|
37
50
|
end
|
51
|
+
alias [] get
|
38
52
|
|
39
53
|
def prod(l, r)
|
40
54
|
return @e if l == r
|
@@ -69,7 +83,11 @@ module AcLibraryRb
|
|
69
83
|
@d[1]
|
70
84
|
end
|
71
85
|
|
72
|
-
|
86
|
+
# apply(pos, f)
|
87
|
+
# apply(l, r, f) -> range_apply(l, r, f)
|
88
|
+
def apply(pos, f, fr = nil)
|
89
|
+
return range_apply(pos, f, fr) if fr
|
90
|
+
|
73
91
|
pos += @size
|
74
92
|
@log.downto(1) { |i| push(pos >> i) }
|
75
93
|
@d[pos] = @mapping.call(f, @d[pos])
|
@@ -133,6 +151,35 @@ module AcLibraryRb
|
|
133
151
|
@n
|
134
152
|
end
|
135
153
|
|
154
|
+
def min_left(r, &g)
|
155
|
+
return 0 if r == 0
|
156
|
+
|
157
|
+
r += @size
|
158
|
+
@log.downto(1) { |i| push((r - 1) >> i) }
|
159
|
+
sm = @e
|
160
|
+
|
161
|
+
loop do
|
162
|
+
r -= 1
|
163
|
+
while r > 1 && r.odd?
|
164
|
+
r /= 2
|
165
|
+
end
|
166
|
+
unless g.call(@op.call(@d[r], sm))
|
167
|
+
while r < @size
|
168
|
+
push(r)
|
169
|
+
r = r * 2 + 1
|
170
|
+
if g.call(@op.call(@d[r], sm))
|
171
|
+
sm = @op.call(@d[r], sm)
|
172
|
+
r -= 1
|
173
|
+
end
|
174
|
+
end
|
175
|
+
return r + 1 - @size
|
176
|
+
end
|
177
|
+
sm = @op.call(@d[r], sm)
|
178
|
+
break if (r & -r) == r
|
179
|
+
end
|
180
|
+
0
|
181
|
+
end
|
182
|
+
|
136
183
|
def update(k)
|
137
184
|
@d[k] = @op.call(@d[2 * k], @d[2 * k + 1])
|
138
185
|
end
|
@@ -3,21 +3,25 @@ module AcLibraryRb
|
|
3
3
|
class Segtree
|
4
4
|
attr_reader :d, :op, :n, :leaf_size, :log
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
# new(e){ |x, y| }
|
7
|
+
# new(v, e){ |x, y| }
|
8
|
+
# new(v, op, e)
|
9
|
+
def initialize(a0, a1 = nil, a2 = nil, &block)
|
10
|
+
if a1.nil?
|
11
|
+
@e, @op = a0, proc(&block)
|
12
|
+
v = []
|
13
|
+
elsif a2.nil?
|
14
|
+
@e, @op = a1, proc(&block)
|
15
|
+
v = (a0.is_a?(Array) ? a0 : [@e] * a0)
|
16
|
+
else
|
17
|
+
@op, @e = a1, a2
|
18
|
+
v = (a0.is_a?(Array) ? a0 : [@e] * a0)
|
12
19
|
end
|
13
20
|
|
14
|
-
@e = e
|
15
|
-
@op = proc(&block)
|
16
|
-
|
17
21
|
@n = v.size
|
18
22
|
@log = (@n - 1).bit_length
|
19
23
|
@leaf_size = 1 << @log
|
20
|
-
@d = Array.new(@leaf_size * 2
|
24
|
+
@d = Array.new(@leaf_size * 2, @e)
|
21
25
|
v.each_with_index { |v_i, i| @d[@leaf_size + i] = v_i }
|
22
26
|
(@leaf_size - 1).downto(1) { |i| update(i) }
|
23
27
|
end
|
@@ -27,10 +31,12 @@ module AcLibraryRb
|
|
27
31
|
@d[q] = x
|
28
32
|
1.upto(@log) { |i| update(q >> i) }
|
29
33
|
end
|
34
|
+
alias []= set
|
30
35
|
|
31
36
|
def get(pos)
|
32
37
|
@d[@leaf_size + pos]
|
33
38
|
end
|
39
|
+
alias [] get
|
34
40
|
|
35
41
|
def prod(l, r)
|
36
42
|
return @e if l == r
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ac-library-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- universato
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-05-
|
11
|
+
date: 2021-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|