ac-library-rb 0.5.2 → 0.6.1
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 +6 -0
- data/README.md +9 -2
- data/ac-library-rb.gemspec +1 -0
- data/bin/lock_lib.rb +5 -1
- data/document_en/dsu.md +2 -2
- data/document_en/max_flow.md +1 -1
- data/document_en/min_cost_flow.md +1 -1
- data/document_en/segtree.md +22 -5
- data/document_en/two_sat.md +1 -1
- data/document_ja/dsu.md +1 -3
- data/document_ja/lazy_segtree.md +9 -7
- 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 +42 -9
- 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/crt.rb +3 -1
- data/lib/dsu.rb +11 -8
- data/lib/fenwick_tree.rb +22 -8
- data/lib/floor_sum.rb +33 -10
- data/lib/lazy_segtree.rb +29 -3
- data/lib/max_flow.rb +10 -4
- data/lib/min_cost_flow.rb +13 -7
- data/lib/scc.rb +21 -13
- data/lib/segtree.rb +28 -22
- data/lib/two_sat.rb +7 -5
- data/lib_helpers/ac-library-rb.rb +24 -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/crt.rb +3 -1
- data/lib_lock/ac-library-rb/dsu.rb +11 -8
- 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 +29 -3
- 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/scc.rb +21 -13
- data/lib_lock/ac-library-rb/segtree.rb +28 -22
- data/lib_lock/ac-library-rb/two_sat.rb +7 -5
- metadata +20 -4
- data/lib_lock/ac-library-rb.rb +0 -22
data/lib/crt.rb
CHANGED
data/lib/dsu.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
# Disjoint Set Union
|
2
2
|
class DSU
|
3
|
-
def initialize(n
|
3
|
+
def initialize(n)
|
4
|
+
@n = n
|
5
|
+
@parent_or_size = Array.new(n, -1)
|
4
6
|
# root node: -1 * component size
|
5
7
|
# otherwise: parent
|
6
|
-
@parent_or_size = Array.new(n, -1)
|
7
8
|
end
|
8
9
|
|
9
|
-
|
10
|
+
attr_reader :parent_or_size, :n
|
10
11
|
|
11
12
|
def merge(a, b)
|
12
13
|
x = leader(a)
|
@@ -19,12 +20,16 @@ class DSU
|
|
19
20
|
end
|
20
21
|
alias unite merge
|
21
22
|
|
22
|
-
def same(a, b)
|
23
|
+
def same?(a, b)
|
23
24
|
leader(a) == leader(b)
|
24
25
|
end
|
25
|
-
alias same
|
26
|
+
alias same same?
|
26
27
|
|
27
28
|
def leader(a)
|
29
|
+
unless 0 <= a && a < @n
|
30
|
+
raise ArgumentError.new, "#{a} is out of range (0...#{@n})"
|
31
|
+
end
|
32
|
+
|
28
33
|
@parent_or_size[a] < 0 ? a : (@parent_or_size[a] = leader(@parent_or_size[a]))
|
29
34
|
end
|
30
35
|
alias root leader
|
@@ -39,6 +44,4 @@ class DSU
|
|
39
44
|
end
|
40
45
|
end
|
41
46
|
|
42
|
-
UnionFind
|
43
|
-
UnionFindTree = DSU
|
44
|
-
DisjointSetUnion = DSU
|
47
|
+
UnionFind = DSU
|
data/lib/fenwick_tree.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
class FenwickTree
|
3
3
|
attr_reader :data, :size
|
4
4
|
|
5
|
-
def initialize(arg
|
5
|
+
def initialize(arg)
|
6
6
|
case arg
|
7
7
|
when Array
|
8
8
|
@size = arg.size
|
@@ -17,7 +17,7 @@ class FenwickTree
|
|
17
17
|
@size = arg
|
18
18
|
@data = Array.new(@size + 1, 0)
|
19
19
|
else
|
20
|
-
raise ArgumentError
|
20
|
+
raise ArgumentError.new("wrong argument. type is Array or Integer")
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -29,8 +29,25 @@ class FenwickTree
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
|
33
|
-
|
32
|
+
# .sum(l, r) # [l, r) <- Original
|
33
|
+
# .sum(r) # [0, r) <- [Experimental]
|
34
|
+
# .sum(l..r) # [l, r] <- [Experimental]
|
35
|
+
def sum(a, b = nil)
|
36
|
+
if b
|
37
|
+
_sum(b) - _sum(a)
|
38
|
+
elsif a.is_a?(Range)
|
39
|
+
l = a.begin
|
40
|
+
l += @size if l < 0
|
41
|
+
if r = a.end
|
42
|
+
r += @size if r < 0
|
43
|
+
r += 1 unless a.exclude_end?
|
44
|
+
else
|
45
|
+
r = @size
|
46
|
+
end
|
47
|
+
_sum(r) - _sum(l)
|
48
|
+
else
|
49
|
+
_sum(a)
|
50
|
+
end
|
34
51
|
end
|
35
52
|
|
36
53
|
def _sum(i)
|
@@ -41,8 +58,5 @@ class FenwickTree
|
|
41
58
|
end
|
42
59
|
res
|
43
60
|
end
|
61
|
+
alias left_sum _sum
|
44
62
|
end
|
45
|
-
|
46
|
-
FeTree = FenwickTree
|
47
|
-
Fetree = FenwickTree
|
48
|
-
BinaryIndexedTree = FenwickTree
|
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
@@ -49,7 +49,18 @@ class LazySegtree
|
|
49
49
|
end
|
50
50
|
alias [] get
|
51
51
|
|
52
|
-
def prod(l, r)
|
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
|
63
|
+
|
53
64
|
return @e if l == r
|
54
65
|
|
55
66
|
l += @size
|
@@ -83,9 +94,22 @@ class LazySegtree
|
|
83
94
|
end
|
84
95
|
|
85
96
|
# apply(pos, f)
|
86
|
-
# apply(l, r, f)
|
97
|
+
# apply(l, r, f) -> range_apply(l, r, f)
|
98
|
+
# apply(l...r, f) -> range_apply(l, r, f) ... [Experimental]
|
87
99
|
def apply(pos, f, fr = nil)
|
88
|
-
|
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
|
89
113
|
|
90
114
|
pos += @size
|
91
115
|
@log.downto(1) { |i| push(pos >> i) }
|
@@ -194,3 +218,5 @@ class LazySegtree
|
|
194
218
|
@lz[k] = @id
|
195
219
|
end
|
196
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/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,14 +2,10 @@
|
|
2
2
|
class Segtree
|
3
3
|
attr_reader :d, :op, :n, :leaf_size, :log
|
4
4
|
|
5
|
-
# new(e){ |x, y| }
|
6
5
|
# new(v, e){ |x, y| }
|
7
6
|
# new(v, op, e)
|
8
|
-
def initialize(a0, a1
|
9
|
-
if
|
10
|
-
@e, @op = a0, proc(&block)
|
11
|
-
v = []
|
12
|
-
elsif a2.nil?
|
7
|
+
def initialize(a0, a1, a2 = nil, &block)
|
8
|
+
if a2.nil?
|
13
9
|
@e, @op = a1, proc(&block)
|
14
10
|
v = (a0.is_a?(Array) ? a0 : [@e] * a0)
|
15
11
|
else
|
@@ -37,7 +33,18 @@ class Segtree
|
|
37
33
|
end
|
38
34
|
alias [] get
|
39
35
|
|
40
|
-
def prod(l, r)
|
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
|
47
|
+
|
41
48
|
return @e if l == r
|
42
49
|
|
43
50
|
sml = @e
|
@@ -127,20 +134,19 @@ class Segtree
|
|
127
134
|
@d[k] = @op.call(@d[2 * k], @d[2 * k + 1])
|
128
135
|
end
|
129
136
|
|
130
|
-
def inspect
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
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
|
143
150
|
end
|
144
151
|
|
145
|
-
SegTree
|
146
|
-
SegmentTree = Segtree
|
152
|
+
SegTree = Segtree
|
data/lib/two_sat.rb
CHANGED
@@ -3,23 +3,25 @@ require_relative './scc.rb'
|
|
3
3
|
# TwoSAT
|
4
4
|
# Reference: https://github.com/atcoder/ac-library/blob/master/atcoder/twosat.hpp
|
5
5
|
class TwoSAT
|
6
|
-
def initialize(n
|
6
|
+
def initialize(n)
|
7
7
|
@n = n
|
8
8
|
@answer = Array.new(n)
|
9
|
-
@scc =
|
9
|
+
@scc = SCC.new(2 * n)
|
10
10
|
end
|
11
11
|
|
12
12
|
attr_reader :answer
|
13
13
|
|
14
14
|
def add_clause(i, f, j, g)
|
15
|
-
|
15
|
+
unless 0 <= i && i < @n and 0 <= j && j < @n
|
16
|
+
raise ArgumentError.new("i:#{i} and j:#{j} must be in (0...#{@n})")
|
17
|
+
end
|
16
18
|
|
17
19
|
@scc.add_edge(2 * i + (f ? 0 : 1), 2 * j + (g ? 1 : 0))
|
18
20
|
@scc.add_edge(2 * j + (g ? 0 : 1), 2 * i + (f ? 1 : 0))
|
19
21
|
nil
|
20
22
|
end
|
21
23
|
|
22
|
-
def satisfiable
|
24
|
+
def satisfiable?
|
23
25
|
id = @scc.send(:scc_ids)[1]
|
24
26
|
@n.times do |i|
|
25
27
|
return false if id[2 * i] == id[2 * i + 1]
|
@@ -28,7 +30,7 @@ class TwoSAT
|
|
28
30
|
end
|
29
31
|
true
|
30
32
|
end
|
31
|
-
alias satisfiable
|
33
|
+
alias satisfiable satisfiable?
|
32
34
|
end
|
33
35
|
|
34
36
|
TwoSat = TwoSAT
|