ac-library-rb 0.5.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 (84) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/unittest.yml +16 -0
  3. data/.gitignore +11 -0
  4. data/.rubocop.yml +198 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE +116 -0
  7. data/README.ja.md +56 -0
  8. data/README.md +41 -0
  9. data/Rakefile +11 -0
  10. data/ac-library-rb.gemspec +32 -0
  11. data/bin/console +8 -0
  12. data/bin/lock_lib.rb +27 -0
  13. data/bin/setup +8 -0
  14. data/document_en/binary_index_tree.md +3 -0
  15. data/document_en/convolution.md +67 -0
  16. data/document_en/dsu.md +132 -0
  17. data/document_en/fenwick_tree.md +99 -0
  18. data/document_en/index.md +79 -0
  19. data/document_en/lazy_segtree.md +141 -0
  20. data/document_en/math.md +104 -0
  21. data/document_en/max_flow.md +165 -0
  22. data/document_en/min_cost_flow.md +132 -0
  23. data/document_en/modint.md +263 -0
  24. data/document_en/priority_queue.md +119 -0
  25. data/document_en/segtree.md +134 -0
  26. data/document_en/string.md +106 -0
  27. data/document_en/two_sat.md +91 -0
  28. data/document_en/union_find.md +3 -0
  29. data/document_ja/convolution.md +64 -0
  30. data/document_ja/dsu.md +183 -0
  31. data/document_ja/fenwick_tree.md +83 -0
  32. data/document_ja/index.md +89 -0
  33. data/document_ja/lazy_segtree.md +135 -0
  34. data/document_ja/math.md +116 -0
  35. data/document_ja/max_flow.md +129 -0
  36. data/document_ja/min_cost_flow.md +105 -0
  37. data/document_ja/modint.md +349 -0
  38. data/document_ja/priority_queue.md +103 -0
  39. data/document_ja/scc.md +65 -0
  40. data/document_ja/segtree.md +145 -0
  41. data/document_ja/string.md +105 -0
  42. data/document_ja/two_sat.md +87 -0
  43. data/lib/ac-library-rb/version.rb +3 -0
  44. data/lib/convolution.rb +124 -0
  45. data/lib/core_ext/modint.rb +19 -0
  46. data/lib/crt.rb +52 -0
  47. data/lib/dsu.rb +44 -0
  48. data/lib/fenwick_tree.rb +48 -0
  49. data/lib/floor_sum.rb +21 -0
  50. data/lib/inv_mod.rb +26 -0
  51. data/lib/lazy_segtree.rb +149 -0
  52. data/lib/lcp_array.rb +23 -0
  53. data/lib/max_flow.rb +137 -0
  54. data/lib/min_cost_flow.rb +143 -0
  55. data/lib/modint.rb +170 -0
  56. data/lib/pow_mod.rb +13 -0
  57. data/lib/priority_queue.rb +89 -0
  58. data/lib/scc.rb +77 -0
  59. data/lib/segtree.rb +140 -0
  60. data/lib/suffix_array.rb +128 -0
  61. data/lib/two_sat.rb +34 -0
  62. data/lib/z_algorithm.rb +32 -0
  63. data/lib_helpers/ac-library-rb/all.rb +22 -0
  64. data/lib_lock/ac-library-rb.rb +22 -0
  65. data/lib_lock/ac-library-rb/convolution.rb +126 -0
  66. data/lib_lock/ac-library-rb/core_ext/modint.rb +19 -0
  67. data/lib_lock/ac-library-rb/crt.rb +54 -0
  68. data/lib_lock/ac-library-rb/dsu.rb +46 -0
  69. data/lib_lock/ac-library-rb/fenwick_tree.rb +50 -0
  70. data/lib_lock/ac-library-rb/floor_sum.rb +23 -0
  71. data/lib_lock/ac-library-rb/inv_mod.rb +28 -0
  72. data/lib_lock/ac-library-rb/lazy_segtree.rb +151 -0
  73. data/lib_lock/ac-library-rb/lcp_array.rb +25 -0
  74. data/lib_lock/ac-library-rb/max_flow.rb +139 -0
  75. data/lib_lock/ac-library-rb/min_cost_flow.rb +145 -0
  76. data/lib_lock/ac-library-rb/modint.rb +172 -0
  77. data/lib_lock/ac-library-rb/pow_mod.rb +15 -0
  78. data/lib_lock/ac-library-rb/priority_queue.rb +91 -0
  79. data/lib_lock/ac-library-rb/scc.rb +79 -0
  80. data/lib_lock/ac-library-rb/segtree.rb +142 -0
  81. data/lib_lock/ac-library-rb/suffix_array.rb +130 -0
  82. data/lib_lock/ac-library-rb/two_sat.rb +36 -0
  83. data/lib_lock/ac-library-rb/z_algorithm.rb +34 -0
  84. metadata +158 -0
@@ -0,0 +1,151 @@
1
+ module AcLibraryRb
2
+ # Segment tree with Lazy propagation
3
+ class LazySegtree
4
+ attr_reader :d, :lz
5
+ attr_accessor :op, :mapping, :composition
6
+
7
+ def initialize(v, e, id, op, mapping, composition)
8
+ v = Array.new(v, e) if v.is_a?(Integer)
9
+
10
+ @n = v.size
11
+ @e = e
12
+ @id = id
13
+ @op = op
14
+ @mapping = mapping
15
+ @composition = composition
16
+
17
+ @log = (@n - 1).bit_length
18
+ @size = 1 << @log
19
+ @d = Array.new(2 * @size, e)
20
+ @lz = Array.new(@size, id)
21
+
22
+ @n.times { |i| @d[@size + i] = v[i] }
23
+ (@size - 1).downto(1) { |i| update(i) }
24
+ end
25
+
26
+ def set(pos, x)
27
+ pos += @size
28
+ @log.downto(1) { |i| push(pos >> i) }
29
+ @d[pos] = x
30
+ 1.upto(@log) { |i| update(pos >> i) }
31
+ end
32
+
33
+ def get(pos)
34
+ pos += @size
35
+ @log.downto(1) { |i| push(pos >> i) }
36
+ @d[pos]
37
+ end
38
+
39
+ def prod(l, r)
40
+ return @e if l == r
41
+
42
+ l += @size
43
+ r += @size
44
+
45
+ @log.downto(1) do |i|
46
+ push(l >> i) if (l >> i) << i != l
47
+ push(r >> i) if (r >> i) << i != r
48
+ end
49
+
50
+ sml = @e
51
+ smr = @e
52
+ while l < r
53
+ if l.odd?
54
+ sml = @op.call(sml, @d[l])
55
+ l += 1
56
+ end
57
+ if r.odd?
58
+ r -= 1
59
+ smr = @op.call(@d[r], smr)
60
+ end
61
+ l >>= 1
62
+ r >>= 1
63
+ end
64
+
65
+ @op.call(sml, smr)
66
+ end
67
+
68
+ def all_prod
69
+ @d[1]
70
+ end
71
+
72
+ def apply(pos, f)
73
+ pos += @size
74
+ @log.downto(1) { |i| push(pos >> i) }
75
+ @d[pos] = @mapping.call(f, @d[pos])
76
+ 1.upto(@log) { |i| update(pos >> i) }
77
+ end
78
+
79
+ def range_apply(l, r, f)
80
+ return if l == r
81
+
82
+ l += @size
83
+ r += @size
84
+
85
+ @log.downto(1) do |i|
86
+ push(l >> i) if (l >> i) << i != l
87
+ push((r - 1) >> i) if (r >> i) << i != r
88
+ end
89
+
90
+ l2 = l
91
+ r2 = r
92
+ while l < r
93
+ (all_apply(l, f); l += 1) if l.odd?
94
+ (r -= 1; all_apply(r, f)) if r.odd?
95
+ l >>= 1
96
+ r >>= 1
97
+ end
98
+ l = l2
99
+ r = r2
100
+
101
+ 1.upto(@log) do |i|
102
+ update(l >> i) if (l >> i) << i != l
103
+ update((r - 1) >> i) if (r >> i) << i != r
104
+ end
105
+ end
106
+
107
+ def max_right(l, &g)
108
+ return @n if l == @n
109
+
110
+ l += @size
111
+ @log.downto(1) { |i| push(l >> i) }
112
+ sm = @e
113
+
114
+ loop do
115
+ while l.even?
116
+ l >>= 1
117
+ end
118
+ unless g.call(@op.call(sm, @d[l]))
119
+ while l < @size
120
+ push(l)
121
+ l <<= 1
122
+ if g.call(@op.call(sm, @d[l]))
123
+ sm = @op.call(sm, @d[l])
124
+ l += 1
125
+ end
126
+ end
127
+ return l - @size
128
+ end
129
+ sm = @op.call(sm, @d[l])
130
+ l += 1
131
+ break if l & -l == l
132
+ end
133
+ @n
134
+ end
135
+
136
+ def update(k)
137
+ @d[k] = @op.call(@d[2 * k], @d[2 * k + 1])
138
+ end
139
+
140
+ def all_apply(k, f)
141
+ @d[k] = @mapping.call(f, @d[k])
142
+ @lz[k] = @composition.call(f, @lz[k]) if k < @size
143
+ end
144
+
145
+ def push(k)
146
+ all_apply(2 * k, @lz[k])
147
+ all_apply(2 * k + 1, @lz[k])
148
+ @lz[k] = @id
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,25 @@
1
+ module AcLibraryRb
2
+ # lcp array for array of integers or string
3
+ def lcp_array(s, sa)
4
+ s = s.bytes if s.is_a?(String)
5
+
6
+ n = s.size
7
+ rnk = [0] * n
8
+ sa.each_with_index{ |sa, id|
9
+ rnk[sa] = id
10
+ }
11
+
12
+ lcp = [0] * (n - 1)
13
+ h = 0
14
+ n.times{ |i|
15
+ h -= 1 if h > 0
16
+ next if rnk[i] == 0
17
+
18
+ j = sa[rnk[i] - 1]
19
+ h += 1 while j + h < n && i + h < n && s[j + h] == s[i + h]
20
+ lcp[rnk[i] - 1] = h
21
+ }
22
+
23
+ return lcp
24
+ end
25
+ end
@@ -0,0 +1,139 @@
1
+ module AcLibraryRb
2
+ # MaxFlowGraph
3
+ class MaxFlow
4
+ def initialize(n = 0)
5
+ @n = n
6
+ @pos = []
7
+ @g = Array.new(n) { [] }
8
+ end
9
+
10
+ def add_edge(from, to, cap)
11
+ edge_number = @pos.size
12
+
13
+ @pos << [from, @g[from].size]
14
+
15
+ from_id = @g[from].size
16
+ to_id = @g[to].size
17
+ to_id += 1 if from == to
18
+ @g[from] << [to, to_id, cap]
19
+ @g[to] << [from, from_id, 0]
20
+
21
+ edge_number
22
+ end
23
+
24
+ def push(edge)
25
+ add_edge(*edge)
26
+ end
27
+ alias << push
28
+
29
+ # return edge = [from, to, cap, flow]
30
+ def [](i)
31
+ _e = @g[@pos[i][0]][@pos[i][1]]
32
+ _re = @g[_e[0]][_e[1]]
33
+ [@pos[i][0], _e[0], _e[-1] + _re[-1], _re[-1]]
34
+ end
35
+ alias get_edge []
36
+ alias edge []
37
+
38
+ def edges
39
+ @pos.map do |(from, id)|
40
+ _e = @g[from][id]
41
+ _re = @g[_e[0]][_e[1]]
42
+ [from, _e[0], _e[-1] + _re[-1], _re[-1]]
43
+ end
44
+ end
45
+
46
+ def change_edge(i, new_cap, new_flow)
47
+ _e = @g[@pos[i][0]][@pos[i][1]]
48
+ _re = @g[_e[0]][_e[1]]
49
+ _e[2] = new_cap - new_flow
50
+ _re[2] = new_flow
51
+ end
52
+
53
+ def flow(s, t, flow_limit = 1 << 64)
54
+ level = Array.new(@n)
55
+ iter = Array.new(@n)
56
+ que = []
57
+
58
+ flow = 0
59
+ while flow < flow_limit
60
+ bfs(s, t, level, que)
61
+ break if level[t] == -1
62
+
63
+ iter.fill(0)
64
+ while flow < flow_limit
65
+ f = dfs(t, flow_limit - flow, s, level, iter)
66
+ break if f == 0
67
+
68
+ flow += f
69
+ end
70
+ end
71
+
72
+ flow
73
+ end
74
+ alias max_flow flow
75
+
76
+ def min_cut(s)
77
+ visited = Array.new(@n, false)
78
+ que = [s]
79
+ while (q = que.shift)
80
+ visited[q] = true
81
+ @g[q].each do |(to, _rev, cap)|
82
+ if cap > 0 && !visited[to]
83
+ visited[to] = true
84
+ que << to
85
+ end
86
+ end
87
+ end
88
+ visited
89
+ end
90
+
91
+ private
92
+
93
+ def bfs(s, t, level, que)
94
+ level.fill(-1)
95
+ level[s] = 0
96
+ que.clear
97
+ que << s
98
+
99
+ while (v = que.shift)
100
+ @g[v].each do |e|
101
+ next if e[2] == 0 || level[e[0]] >= 0
102
+
103
+ level[e[0]] = level[v] + 1
104
+ return nil if e[0] == t
105
+
106
+ que << e[0]
107
+ end
108
+ end
109
+ end
110
+
111
+ def dfs(v, up, s, level, iter)
112
+ return up if v == s
113
+
114
+ res = 0
115
+ level_v = level[v]
116
+
117
+ while iter[v] < @g[v].size
118
+ i = iter[v]
119
+ e = @g[v][i]
120
+ cap = @g[e[0]][e[1]][2]
121
+ if level_v > level[e[0]] && cap > 0
122
+ d = dfs(e[0], (up - res < cap ? up - res : cap), s, level, iter)
123
+ if d > 0
124
+ @g[v][i][2] += d
125
+ @g[e[0]][e[1]][2] -= d
126
+ res += d
127
+ break if res == up
128
+ end
129
+ end
130
+ iter[v] += 1
131
+ end
132
+
133
+ res
134
+ end
135
+ end
136
+
137
+ MaxFlowGraph = MaxFlow
138
+ MFGraph = MaxFlow
139
+ end
@@ -0,0 +1,145 @@
1
+ module AcLibraryRb
2
+ require_relative './priority_queue.rb'
3
+
4
+ # Min Cost Flow Grapsh
5
+ class MinCostFlow
6
+ def initialize(n)
7
+ @n = n
8
+ @pos = []
9
+ @g_to = Array.new(n) { [] }
10
+ @g_rev = Array.new(n) { [] }
11
+ @g_cap = Array.new(n) { [] }
12
+ @g_cost = Array.new(n) { [] }
13
+ @pv = Array.new(n)
14
+ @pe = Array.new(n)
15
+ @dual = Array.new(n) { 0 }
16
+ end
17
+
18
+ def add_edge(from, to, cap, cost)
19
+ edge_number = @pos.size
20
+
21
+ @pos << [from, @g_to[from].size]
22
+
23
+ from_id = @g_to[from].size
24
+ to_id = @g_to[to].size
25
+ to_id += 1 if from == to
26
+
27
+ @g_to[from] << to
28
+ @g_rev[from] << to_id
29
+ @g_cap[from] << cap
30
+ @g_cost[from] << cost
31
+
32
+ @g_to[to] << from
33
+ @g_rev[to] << from_id
34
+ @g_cap[to] << 0
35
+ @g_cost[to] << -cost
36
+
37
+ edge_number
38
+ end
39
+
40
+ def get_edge(i)
41
+ from, id = @pos[i]
42
+ to = @g_to[from][id]
43
+ rid = @g_rev[from][id]
44
+ [from, to, @g_cap[from][id] + @g_cap[to][rid], @g_cap[to][rid], @g_cost[from][id]]
45
+ end
46
+ alias edge get_edge
47
+ alias [] get_edge
48
+
49
+ def edges
50
+ @pos.map do |(from, id)|
51
+ to = @g_to[from][id]
52
+ rid = @g_rev[from][id]
53
+ [from, to, @g_cap[from][id] + @g_cap[to][rid], @g_cap[to][rid], @g_cost[from][id]]
54
+ end
55
+ end
56
+
57
+ def flow(s, t, flow_limit = Float::MAX)
58
+ slope(s, t, flow_limit).last
59
+ end
60
+ alias min_cost_max_flow flow
61
+
62
+ def dual_ref(s, t)
63
+ dist = Array.new(@n, Float::MAX)
64
+ @pv.fill(-1)
65
+ @pe.fill(-1)
66
+ vis = Array.new(@n, false)
67
+
68
+ que = PriorityQueue.new { |par, chi| par[0] < chi[0] }
69
+ dist[s] = 0
70
+ que.push([0, s])
71
+
72
+ while (v = que.pop)
73
+ v = v[1]
74
+
75
+ next if vis[v]
76
+
77
+ vis[v] = true
78
+ break if v == t
79
+
80
+ @g_to[v].size.times do |i|
81
+ to = @g_to[v][i]
82
+ next if vis[to] || @g_cap[v][i] == 0
83
+
84
+ cost = @g_cost[v][i] - @dual[to] + @dual[v]
85
+ next unless dist[to] - dist[v] > cost
86
+
87
+ dist[to] = dist[v] + cost
88
+ @pv[to] = v
89
+ @pe[to] = i
90
+ que.push([dist[to], to])
91
+ end
92
+ end
93
+
94
+ return false unless vis[t]
95
+
96
+ @n.times do |i|
97
+ next unless vis[i]
98
+
99
+ @dual[i] -= dist[t] - dist[i]
100
+ end
101
+
102
+ true
103
+ end
104
+
105
+ def slope(s, t, flow_limit = Float::MAX)
106
+ flow = 0
107
+ cost = 0
108
+ prev_cost = -1
109
+ result = [[flow, cost]]
110
+
111
+ while flow < flow_limit
112
+ break unless dual_ref(s, t)
113
+
114
+ c = flow_limit - flow
115
+ v = t
116
+ while v != s
117
+ c = @g_cap[@pv[v]][@pe[v]] if c > @g_cap[@pv[v]][@pe[v]]
118
+ v = @pv[v]
119
+ end
120
+
121
+ v = t
122
+ while v != s
123
+ nv = @pv[v]
124
+ id = @pe[v]
125
+ @g_cap[nv][id] -= c
126
+ @g_cap[v][@g_rev[nv][id]] += c
127
+ v = nv
128
+ end
129
+
130
+ d = -@dual[s]
131
+ flow += c
132
+ cost += c * d
133
+ result.pop if prev_cost == d
134
+ result << [flow, cost]
135
+ prev_cost = d
136
+ end
137
+
138
+ result
139
+ end
140
+ alias min_cost_slop slope
141
+ end
142
+
143
+ MCF = MinCostFlow
144
+ MCFGraph = MinCostFlow
145
+ end