ac-library-rb 0.5.0 → 0.6.0

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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +12 -0
  3. data/README.ja.md +102 -4
  4. data/README.md +73 -1
  5. data/Rakefile +2 -1
  6. data/ac-library-rb.gemspec +3 -2
  7. data/bin/lock_lib.rb +13 -7
  8. data/document_en/dsu.md +2 -2
  9. data/document_en/lazy_segtree.md +20 -4
  10. data/document_en/max_flow.md +1 -1
  11. data/document_en/min_cost_flow.md +1 -1
  12. data/document_en/segtree.md +36 -3
  13. data/document_en/two_sat.md +1 -1
  14. data/document_ja/dsu.md +1 -3
  15. data/document_ja/lazy_segtree.md +63 -19
  16. data/document_ja/max_flow.md +1 -1
  17. data/document_ja/min_cost_flow.md +1 -1
  18. data/document_ja/scc.md +4 -3
  19. data/document_ja/segtree.md +49 -8
  20. data/document_ja/two_sat.md +1 -1
  21. data/lib/ac-library-rb/version.rb +1 -1
  22. data/lib/convolution.rb +21 -0
  23. data/lib/core_ext/all.rb +11 -0
  24. data/lib/dsu.rb +9 -6
  25. data/lib/fenwick_tree.rb +22 -8
  26. data/lib/floor_sum.rb +33 -10
  27. data/lib/lazy_segtree.rb +83 -10
  28. data/lib/max_flow.rb +10 -4
  29. data/lib/min_cost_flow.rb +13 -7
  30. data/lib/modint.rb +3 -1
  31. data/lib/scc.rb +21 -13
  32. data/lib/segtree.rb +38 -26
  33. data/lib/suffix_array.rb +8 -8
  34. data/lib/two_sat.rb +5 -3
  35. data/lib_lock/ac-library-rb.rb +2 -0
  36. data/lib_lock/ac-library-rb/convolution.rb +21 -0
  37. data/lib_lock/ac-library-rb/core_ext/all.rb +11 -0
  38. data/lib_lock/ac-library-rb/core_ext/modint.rb +3 -3
  39. data/lib_lock/ac-library-rb/dsu.rb +9 -6
  40. data/lib_lock/ac-library-rb/fenwick_tree.rb +22 -8
  41. data/lib_lock/ac-library-rb/floor_sum.rb +33 -10
  42. data/lib_lock/ac-library-rb/lazy_segtree.rb +83 -10
  43. data/lib_lock/ac-library-rb/max_flow.rb +10 -4
  44. data/lib_lock/ac-library-rb/min_cost_flow.rb +13 -7
  45. data/lib_lock/ac-library-rb/modint.rb +3 -1
  46. data/lib_lock/ac-library-rb/scc.rb +21 -13
  47. data/lib_lock/ac-library-rb/segtree.rb +38 -26
  48. data/lib_lock/ac-library-rb/suffix_array.rb +8 -8
  49. data/lib_lock/ac-library-rb/two_sat.rb +5 -3
  50. metadata +20 -4
data/lib/floor_sum.rb CHANGED
@@ -1,21 +1,44 @@
1
1
  def floor_sum(n, m, a, b)
2
+ raise ArgumentError if n < 0 || m < 1
3
+
2
4
  res = 0
3
5
 
4
- if a >= m
5
- res += (n - 1) * n * (a / m) / 2
6
- a %= m
6
+ if a < 0
7
+ a2 = a % m
8
+ res -= n * (n - 1) / 2 * ((a2 - a) / m)
9
+ a = a2
7
10
  end
8
11
 
9
- if b >= m
10
- res += n * (b / m)
11
- b %= m
12
+ if b < 0
13
+ b2 = b % m
14
+ res -= n * ((b2 - b) / m)
15
+ b = b2
12
16
  end
13
17
 
14
- y_max = (a * n + b) / m
18
+ res + floor_sum_unsigned(n, m, a, b)
19
+ end
20
+
21
+ def floor_sum_unsigned(n, m, a, b)
22
+ res = 0
23
+
24
+ while true
25
+ if a >= m
26
+ res += n * (n - 1) / 2 * (a / m)
27
+ a %= m
28
+ end
29
+
30
+ if b >= m
31
+ res += n * (b / m)
32
+ b %= m
33
+ end
15
34
 
16
- return res if y_max == 0
35
+ y_max = a * n + b
36
+ break if y_max < m
37
+
38
+ n = y_max / m
39
+ b = y_max % m
40
+ m, a = a, m
41
+ end
17
42
 
18
- x_max = (m * y_max - b + a - 1) / a
19
- res += (n - x_max) * y_max + floor_sum(y_max, a, m, a * x_max - m * y_max + b)
20
43
  res
21
44
  end
data/lib/lazy_segtree.rb CHANGED
@@ -1,17 +1,21 @@
1
1
  # Segment tree with Lazy propagation
2
2
  class LazySegtree
3
- attr_reader :d, :lz
3
+ attr_reader :d, :lz, :e, :id
4
4
  attr_accessor :op, :mapping, :composition
5
5
 
6
- def initialize(v, e, id, op, mapping, composition)
7
- v = Array.new(v, e) if v.is_a?(Integer)
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,20 +26,41 @@ 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
51
+
52
+ def prod(l, r = nil)
53
+ if r.nil? # if 1st argument l is Range
54
+ if r = l.end
55
+ r += @n if r < 0
56
+ r += 1 unless l.exclude_end?
57
+ else
58
+ r = @n
59
+ end
60
+ l = l.begin
61
+ l += @n if l < 0
62
+ end
37
63
 
38
- def prod(l, r)
39
64
  return @e if l == r
40
65
 
41
66
  l += @size
@@ -68,7 +93,24 @@ class LazySegtree
68
93
  @d[1]
69
94
  end
70
95
 
71
- def apply(pos, f)
96
+ # apply(pos, f)
97
+ # apply(l, r, f) -> range_apply(l, r, f)
98
+ # apply(l...r, f) -> range_apply(l, r, f) ... [Experimental]
99
+ def apply(pos, f, fr = nil)
100
+ if fr
101
+ return range_apply(pos, f, fr)
102
+ elsif pos.is_a?(Range)
103
+ l = pos.begin
104
+ l += @n if l < 0
105
+ if r = pos.end
106
+ r += @n if r < 0
107
+ r += 1 unless pos.exclude_end?
108
+ else
109
+ r = @n
110
+ end
111
+ return range_apply(l, r, f)
112
+ end
113
+
72
114
  pos += @size
73
115
  @log.downto(1) { |i| push(pos >> i) }
74
116
  @d[pos] = @mapping.call(f, @d[pos])
@@ -132,6 +174,35 @@ class LazySegtree
132
174
  @n
133
175
  end
134
176
 
177
+ def min_left(r, &g)
178
+ return 0 if r == 0
179
+
180
+ r += @size
181
+ @log.downto(1) { |i| push((r - 1) >> i) }
182
+ sm = @e
183
+
184
+ loop do
185
+ r -= 1
186
+ while r > 1 && r.odd?
187
+ r /= 2
188
+ end
189
+ unless g.call(@op.call(@d[r], sm))
190
+ while r < @size
191
+ push(r)
192
+ r = r * 2 + 1
193
+ if g.call(@op.call(@d[r], sm))
194
+ sm = @op.call(@d[r], sm)
195
+ r -= 1
196
+ end
197
+ end
198
+ return r + 1 - @size
199
+ end
200
+ sm = @op.call(@d[r], sm)
201
+ break if (r & -r) == r
202
+ end
203
+ 0
204
+ end
205
+
135
206
  def update(k)
136
207
  @d[k] = @op.call(@d[2 * k], @d[2 * k + 1])
137
208
  end
@@ -147,3 +218,5 @@ class LazySegtree
147
218
  @lz[k] = @id
148
219
  end
149
220
  end
221
+
222
+ LazySegTree = LazySegtree
data/lib/max_flow.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # MaxFlowGraph
2
2
  class MaxFlow
3
- def initialize(n = 0)
3
+ def initialize(n)
4
4
  @n = n
5
5
  @pos = []
6
6
  @g = Array.new(n) { [] }
@@ -20,6 +20,15 @@ class MaxFlow
20
20
  edge_number
21
21
  end
22
22
 
23
+ def add_edges(edges)
24
+ edges.each{ |from, to, cap| add_edge(from, to, cap) }
25
+ self
26
+ end
27
+
28
+ def add(x, to = nil, cap = nil)
29
+ cap ? add_edge(x, to, cap) : add_edges(x)
30
+ end
31
+
23
32
  def push(edge)
24
33
  add_edge(*edge)
25
34
  end
@@ -132,6 +141,3 @@ class MaxFlow
132
141
  res
133
142
  end
134
143
  end
135
-
136
- MaxFlowGraph = MaxFlow
137
- MFGraph = MaxFlow
data/lib/min_cost_flow.rb CHANGED
@@ -11,7 +11,7 @@ class MinCostFlow
11
11
  @g_cost = Array.new(n) { [] }
12
12
  @pv = Array.new(n)
13
13
  @pe = Array.new(n)
14
- @dual = Array.new(n) { 0 }
14
+ @dual = Array.new(n, 0)
15
15
  end
16
16
 
17
17
  def add_edge(from, to, cap, cost)
@@ -36,6 +36,15 @@ class MinCostFlow
36
36
  edge_number
37
37
  end
38
38
 
39
+ def add_edges(edges)
40
+ edges.each{ |from, to, cap, cost| add_edge(from, to, cap, cost) }
41
+ self
42
+ end
43
+
44
+ def add(x, to = nil, cap = nil, cost = nil)
45
+ cost ? add_edge(x, to, cap, cost) : add_edges(x)
46
+ end
47
+
39
48
  def get_edge(i)
40
49
  from, id = @pos[i]
41
50
  to = @g_to[from][id]
@@ -104,7 +113,7 @@ class MinCostFlow
104
113
  def slope(s, t, flow_limit = Float::MAX)
105
114
  flow = 0
106
115
  cost = 0
107
- prev_cost = -1
116
+ prev_cost_per_flow = -1
108
117
  result = [[flow, cost]]
109
118
 
110
119
  while flow < flow_limit
@@ -129,15 +138,12 @@ class MinCostFlow
129
138
  d = -@dual[s]
130
139
  flow += c
131
140
  cost += c * d
132
- result.pop if prev_cost == d
141
+ result.pop if prev_cost_per_flow == d
133
142
  result << [flow, cost]
134
- prev_cost = d
143
+ prev_cost_per_flow = d
135
144
  end
136
145
 
137
146
  result
138
147
  end
139
148
  alias min_cost_slop slope
140
149
  end
141
-
142
- MCF = MinCostFlow
143
- MCFGraph = MinCostFlow
data/lib/modint.rb CHANGED
@@ -161,7 +161,9 @@ class ModInt < Numeric
161
161
 
162
162
  def inv_internal(a)
163
163
  if $_mod_is_prime
164
- a != 0 ? a.pow($_mod - 2, $_mod) : raise(RangeError, 'no inverse')
164
+ raise(RangeError, 'no inverse') if a == 0
165
+
166
+ a.pow($_mod - 2, $_mod)
165
167
  else
166
168
  g, x = ModInt.inv_gcd(a, $_mod)
167
169
  g == 1 ? x : raise(RangeError, 'no inverse')
data/lib/scc.rb CHANGED
@@ -1,15 +1,29 @@
1
1
  # Strongly Connected Components
2
- class SCCGraph
2
+ class SCC
3
3
  # initialize graph with n vertices
4
- def initialize(n = 0)
5
- @n, @edges = n, []
4
+ def initialize(n)
5
+ @n = n
6
+ @edges = []
6
7
  end
7
8
 
8
9
  # add directed edge
9
10
  def add_edge(from, to)
10
- raise "invalid params" unless (0...@n).include? from and (0...@n).include? to
11
+ unless 0 <= from && from < @n and 0 <= to && to < @n
12
+ msg = "Wrong params: from=#{from} and to=#{to} must be in 0...#{@n}"
13
+ raise ArgumentError.new(msg)
14
+ end
11
15
 
12
16
  @edges << [from, to]
17
+ self
18
+ end
19
+
20
+ def add_edges(edges)
21
+ edges.each{ |from, to| add_edge(from, to) }
22
+ self
23
+ end
24
+
25
+ def add(x, to = nil)
26
+ to ? add_edge(x, to) : add_edges(x)
13
27
  end
14
28
 
15
29
  # returns list of strongly connected components
@@ -17,10 +31,8 @@ class SCCGraph
17
31
  # O(@n + @edges.size)
18
32
  def scc
19
33
  group_num, ids = scc_ids
20
- counts = [0] * group_num
21
- ids.each { |x| counts[x] += 1 }
22
34
  groups = Array.new(group_num) { [] }
23
- ids.each_with_index { |x, i| groups[x] << i }
35
+ ids.each_with_index { |id, i| groups[id] << i }
24
36
  groups
25
37
  end
26
38
 
@@ -59,7 +71,8 @@ class SCCGraph
59
71
  end
60
72
 
61
73
  def csr
62
- start, elist = [0] * (@n + 1), [nil] * @edges.size
74
+ start = [0] * (@n + 1)
75
+ elist = [nil] * @edges.size
63
76
  @edges.each { |(i, _)| start[i + 1] += 1 }
64
77
  @n.times { |i| start[i + 1] += start[i] }
65
78
  counter = start.dup
@@ -70,8 +83,3 @@ class SCCGraph
70
83
  [start, elist]
71
84
  end
72
85
  end
73
-
74
- # class alias
75
- StronglyConnectedComponents = SCCGraph
76
- SCC = SCCGraph
77
- SCCG = SCCGraph
data/lib/segtree.rb CHANGED
@@ -2,21 +2,21 @@
2
2
  class Segtree
3
3
  attr_reader :d, :op, :n, :leaf_size, :log
4
4
 
5
- def initialize(arg = 0, e, &block)
6
- case arg
7
- when Integer
8
- v = Array.new(arg) { e }
9
- when Array
10
- v = arg
5
+ # new(v, e){ |x, y| }
6
+ # new(v, op, e)
7
+ def initialize(a0, a1, a2 = nil, &block)
8
+ if a2.nil?
9
+ @e, @op = a1, proc(&block)
10
+ v = (a0.is_a?(Array) ? a0 : [@e] * a0)
11
+ else
12
+ @op, @e = a1, a2
13
+ v = (a0.is_a?(Array) ? a0 : [@e] * a0)
11
14
  end
12
15
 
13
- @e = e
14
- @op = proc(&block)
15
-
16
16
  @n = v.size
17
17
  @log = (@n - 1).bit_length
18
18
  @leaf_size = 1 << @log
19
- @d = Array.new(@leaf_size * 2) { e }
19
+ @d = Array.new(@leaf_size * 2, @e)
20
20
  v.each_with_index { |v_i, i| @d[@leaf_size + i] = v_i }
21
21
  (@leaf_size - 1).downto(1) { |i| update(i) }
22
22
  end
@@ -26,12 +26,25 @@ class Segtree
26
26
  @d[q] = x
27
27
  1.upto(@log) { |i| update(q >> i) }
28
28
  end
29
+ alias []= set
29
30
 
30
31
  def get(pos)
31
32
  @d[@leaf_size + pos]
32
33
  end
34
+ alias [] get
35
+
36
+ def prod(l, r = nil)
37
+ if r.nil? # if 1st argument l is Range
38
+ if r = l.end
39
+ r += @n if r < 0
40
+ r += 1 unless l.exclude_end?
41
+ else
42
+ r = @n
43
+ end
44
+ l = l.begin
45
+ l += @n if l < 0
46
+ end
33
47
 
34
- def prod(l, r)
35
48
  return @e if l == r
36
49
 
37
50
  sml = @e
@@ -121,20 +134,19 @@ class Segtree
121
134
  @d[k] = @op.call(@d[2 * k], @d[2 * k + 1])
122
135
  end
123
136
 
124
- def inspect
125
- t = 0
126
- res = "SegmentTree @e = #{@e}, @n = #{@n}, @leaf_size = #{@leaf_size} @op = #{@op}\n "
127
- a = @d[1, @d.size - 1]
128
- a.each_with_index do |e, i|
129
- res << e.to_s << ' '
130
- if t == i && i < @leaf_size
131
- res << "\n "
132
- t = t * 2 + 2
133
- end
134
- end
135
- res
136
- end
137
+ # def inspect # for debug
138
+ # t = 0
139
+ # res = "Segtree @e = #{@e}, @n = #{@n}, @leaf_size = #{@leaf_size} @op = #{@op}\n "
140
+ # a = @d[1, @d.size - 1]
141
+ # a.each_with_index do |e, i|
142
+ # res << e.to_s << ' '
143
+ # if t == i && i < @leaf_size
144
+ # res << "\n "
145
+ # t = t * 2 + 2
146
+ # end
147
+ # end
148
+ # res
149
+ # end
137
150
  end
138
151
 
139
- SegTree = Segtree
140
- SegmentTree = Segtree
152
+ SegTree = Segtree
data/lib/suffix_array.rb CHANGED
@@ -76,9 +76,7 @@ def sa_is(s, upper)
76
76
  end_l = lms[lms_map[l] + 1] || n
77
77
  end_r = lms[lms_map[r] + 1] || n
78
78
  same = true
79
- if end_l - l != end_r - r
80
- same = false
81
- else
79
+ if end_l - l == end_r - r
82
80
  while l < end_l
83
81
  break if s[l] != s[r]
84
82
 
@@ -86,6 +84,8 @@ def sa_is(s, upper)
86
84
  r += 1
87
85
  end
88
86
  same = false if l == n || s[l] != s[r]
87
+ else
88
+ same = false
89
89
  end
90
90
  rec_upper += 1 if not same
91
91
  rec_s[lms_map[sorted_lms[i]]] = rec_upper
@@ -100,7 +100,11 @@ end
100
100
 
101
101
  # suffix array for array of integers or string
102
102
  def suffix_array(s, upper = nil)
103
- if not upper
103
+ if upper
104
+ s.each{ |s|
105
+ raise ArgumentError if s < 0 || upper < s
106
+ }
107
+ else
104
108
  case s
105
109
  when Array
106
110
  # compression
@@ -118,10 +122,6 @@ def suffix_array(s, upper = nil)
118
122
  upper = 255
119
123
  s = s.bytes
120
124
  end
121
- else
122
- s.each{ |s|
123
- raise ArgumentError if s < 0 || upper < s
124
- }
125
125
  end
126
126
 
127
127
  return sa_is(s, upper)