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.
- checksums.yaml +4 -4
- data/.rubocop.yml +12 -0
- data/README.ja.md +102 -4
- data/README.md +73 -1
- data/Rakefile +2 -1
- data/ac-library-rb.gemspec +3 -2
- data/bin/lock_lib.rb +13 -7
- data/document_en/dsu.md +2 -2
- data/document_en/lazy_segtree.md +20 -4
- data/document_en/max_flow.md +1 -1
- data/document_en/min_cost_flow.md +1 -1
- data/document_en/segtree.md +36 -3
- data/document_en/two_sat.md +1 -1
- data/document_ja/dsu.md +1 -3
- data/document_ja/lazy_segtree.md +63 -19
- data/document_ja/max_flow.md +1 -1
- data/document_ja/min_cost_flow.md +1 -1
- data/document_ja/scc.md +4 -3
- data/document_ja/segtree.md +49 -8
- data/document_ja/two_sat.md +1 -1
- data/lib/ac-library-rb/version.rb +1 -1
- data/lib/convolution.rb +21 -0
- data/lib/core_ext/all.rb +11 -0
- data/lib/dsu.rb +9 -6
- data/lib/fenwick_tree.rb +22 -8
- data/lib/floor_sum.rb +33 -10
- data/lib/lazy_segtree.rb +83 -10
- data/lib/max_flow.rb +10 -4
- data/lib/min_cost_flow.rb +13 -7
- data/lib/modint.rb +3 -1
- data/lib/scc.rb +21 -13
- data/lib/segtree.rb +38 -26
- data/lib/suffix_array.rb +8 -8
- data/lib/two_sat.rb +5 -3
- data/lib_lock/ac-library-rb.rb +2 -0
- data/lib_lock/ac-library-rb/convolution.rb +21 -0
- data/lib_lock/ac-library-rb/core_ext/all.rb +11 -0
- data/lib_lock/ac-library-rb/core_ext/modint.rb +3 -3
- data/lib_lock/ac-library-rb/dsu.rb +9 -6
- data/lib_lock/ac-library-rb/fenwick_tree.rb +22 -8
- data/lib_lock/ac-library-rb/floor_sum.rb +33 -10
- data/lib_lock/ac-library-rb/lazy_segtree.rb +83 -10
- data/lib_lock/ac-library-rb/max_flow.rb +10 -4
- data/lib_lock/ac-library-rb/min_cost_flow.rb +13 -7
- data/lib_lock/ac-library-rb/modint.rb +3 -1
- data/lib_lock/ac-library-rb/scc.rb +21 -13
- data/lib_lock/ac-library-rb/segtree.rb +38 -26
- data/lib_lock/ac-library-rb/suffix_array.rb +8 -8
- data/lib_lock/ac-library-rb/two_sat.rb +5 -3
- 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
|
5
|
-
|
6
|
-
a
|
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
|
10
|
-
|
11
|
-
b
|
12
|
+
if b < 0
|
13
|
+
b2 = b % m
|
14
|
+
res -= n * ((b2 - b) / m)
|
15
|
+
b = b2
|
12
16
|
end
|
13
17
|
|
14
|
-
|
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
|
-
|
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
|
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,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
|
-
|
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
|
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
|
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
|
-
|
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
|
141
|
+
result.pop if prev_cost_per_flow == d
|
133
142
|
result << [flow, cost]
|
134
|
-
|
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
|
-
|
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
|
2
|
+
class SCC
|
3
3
|
# initialize graph with n vertices
|
4
|
-
def initialize(n
|
5
|
-
@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
|
-
|
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 { |
|
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
|
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
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
v =
|
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
|
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
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
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
|
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
|
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
|
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)
|