ac-library-rb 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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)