結果
問題 | No.922 東北きりきざむたん |
ユーザー | yuruhiya |
提出日時 | 2021-07-23 16:36:47 |
言語 | Crystal (1.11.2) |
結果 |
AC
|
実行時間 | 217 ms / 2,000 ms |
コード長 | 16,115 bytes |
コンパイル時間 | 13,700 ms |
コンパイル使用メモリ | 305,176 KB |
実行使用メモリ | 69,088 KB |
最終ジャッジ日時 | 2024-07-18 12:00:39 |
合計ジャッジ時間 | 19,115 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge4 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
6,816 KB |
testcase_01 | AC | 2 ms
6,944 KB |
testcase_02 | AC | 2 ms
6,944 KB |
testcase_03 | AC | 1 ms
6,944 KB |
testcase_04 | AC | 3 ms
6,944 KB |
testcase_05 | AC | 2 ms
6,940 KB |
testcase_06 | AC | 3 ms
6,940 KB |
testcase_07 | AC | 3 ms
6,940 KB |
testcase_08 | AC | 3 ms
6,940 KB |
testcase_09 | AC | 105 ms
35,292 KB |
testcase_10 | AC | 36 ms
8,960 KB |
testcase_11 | AC | 82 ms
19,888 KB |
testcase_12 | AC | 131 ms
51,132 KB |
testcase_13 | AC | 37 ms
15,116 KB |
testcase_14 | AC | 176 ms
50,756 KB |
testcase_15 | AC | 132 ms
60,388 KB |
testcase_16 | AC | 171 ms
30,620 KB |
testcase_17 | AC | 177 ms
29,808 KB |
testcase_18 | AC | 171 ms
30,484 KB |
testcase_19 | AC | 167 ms
30,180 KB |
testcase_20 | AC | 168 ms
30,336 KB |
testcase_21 | AC | 157 ms
23,632 KB |
testcase_22 | AC | 162 ms
24,420 KB |
testcase_23 | AC | 195 ms
34,064 KB |
testcase_24 | AC | 202 ms
34,924 KB |
testcase_25 | AC | 176 ms
43,140 KB |
testcase_26 | AC | 179 ms
42,992 KB |
testcase_27 | AC | 185 ms
43,160 KB |
testcase_28 | AC | 192 ms
69,088 KB |
testcase_29 | AC | 217 ms
59,332 KB |
ソースコード
# require "/scanner" # ### Specifications # # ```plain # Inside input macro | Expanded code # ----------------------------------------------+--------------------------------------- # Uppercase string: Int32, Int64, Float64, etc. | {}.new(Scanner.s) # s | Scanner.s # c | Scanner.c # Other lowercase string: i, i64, f, etc. | Scanner.s.to_{} # operator[]: type[size] | Array.new(input(size)) { input(type) } # Tuple literal: {t1, t2, t3} | {input(t1), input(t2), input(t3)} # Array literal: [t1, t2, t3] | [input(t1), input(t2), input(t3)] # Range literal: t1..t2 | input(t1)..input(t2) # If: cond ? t1 : t2 | cond ? input(t1) : input(t2) # Assign: target = value | target = input(value) # ``` # # ### Examples # # Input: # ```plain # 5 3 # foo bar # 1 2 3 4 5 # ``` # ``` # n, m = input(Int32, Int64) # => {5, 10i64} # input(String, Char[m]) # => {"foo", ['b', 'a', 'r']} # input(Int32[n]) # => [1, 2, 3, 4, 5] # ``` # ``` # n, m = input(i, i64) # => {5, 10i64} # input(s, c[m]) # => {"foo", ['b', 'a', 'r']} # input(i[n]) # => [1, 2, 3, 4, 5] # ``` # # Input: # ```plain # 2 3 # 1 2 3 # 4 5 6 # ``` # # ``` # h, w = input(i, i) # => {2, 3} # input(i[h, w]) # => [[1, 2, 3], [4, 5, 6]] # ``` # ``` # input(i[i][i]) # => [[1, 2, 3], [4, 5, 6]] # ``` # # Input: # ```plain # 5 3 # 3 1 4 2 5 # 1 2 # 2 3 # 3 1 # ``` # ``` # n, m = input(i, i) # => {5, 3} # input(i.pred[n]) # => [2, 0, 3, 1, 4] # input({i - 1, i - 1}[m]) # => [{0, 1}, {1, 2}, {2, 0}] # ``` # # Input: # ```plain # 3 # 1 2 # 2 2 # 3 2 # ``` # ``` # input({tmp = i, tmp == 1 ? i : i.pred}[i]) # => [{1, 2}, {2, 1}, {3, 1}] # ``` # # Input: # ```plain # 3 # 1 2 # 2 3 # 3 1 # ``` # ``` # n = input(i) # input_column({i, i}, n) # => {[1, 2, 3], [2, 3, 1]} # ``` class Scanner private def self.skip_to_not_space peek = STDIN.peek not_space = peek.index { |x| x != 32 && x != 10 } || peek.size STDIN.skip(not_space) end def self.c skip_to_not_space STDIN.read_char.not_nil! end def self.s skip_to_not_space peek = STDIN.peek if index = peek.index { |x| x == 32 || x == 10 } STDIN.skip(index + 1) return String.new(peek[0, index]) end String.build do |buffer| loop do buffer.write peek STDIN.skip(peek.size) peek = STDIN.peek break if peek.empty? if index = peek.index { |x| x == 32 || x == 10 } buffer.write peek[0, index] STDIN.skip(index) break end end end end end macro internal_input(type, else_ast) {% if Scanner.class.has_method?(type.id) %} Scanner.{{type.id}} {% elsif type.stringify == "String" %} Scanner.s {% elsif type.stringify == "Char" %} Scanner.c {% elsif type.stringify =~ /[A-Z][a-z0-9_]*/ %} {{type.id}}.new(Scanner.s) {% elsif String.has_method?("to_#{type}".id) %} Scanner.s.to_{{type.id}} {% else %} {{else_ast}} {% end %} end macro internal_input_array(type, args) {% for i in 0...args.size %} %size{i} = input({{args[i]}}) {% end %} {% begin %} {% for i in 0...args.size %} Array.new(%size{i}) { {% end %} input({{type.id}}) {% for i in 0...args.size %} } {% end %} {% end %} end macro input(type) {% if type.is_a?(Call) %} {% if type.receiver.is_a?(Nop) %} internal_input( {{type.name}}, {{type.name}}( {% for argument in type.args %} input({{argument}}), {% end %} ) ) {% elsif type.name.stringify == "[]" %} internal_input_array({{type.receiver}}, {{type.args}}) {% else %} input({{type.receiver}}).{{type.name.id}}( {% for argument in type.args %} input({{argument}}), {% end %} ) {{type.block}} {% end %} {% elsif type.is_a?(TupleLiteral) %} { {% for i in 0...type.size %} input({{type[i]}}), {% end %} } {% elsif type.is_a?(ArrayLiteral) %} [ {% for i in 0...type.size %} input({{type[i]}}), {% end %} ] {% elsif type.is_a?(RangeLiteral) %} Range.new(input({{type.begin}}), input({{type.end}}), {{type.excludes_end?}}) {% elsif type.is_a?(If) %} {{type.cond}} ? input({{type.then}}) : input({{type.else}}) {% elsif type.is_a?(Assign) %} {{type.target}} = input({{type.value}}) {% else %} internal_input({{type.id}}, {{type.id}}) {% end %} end macro input(*types) { {% for type in types %} input({{type}}), {% end %} } end macro input_column(types, size) {% for type, i in types %} first_value = input({{type}}) %array{i} = Array(typeof(first_value)).new({{size}}) %array{i} << first_value {% end %} {{size}}.pred.times do {% for type, i in types %} %array{i} << input({{type}}) {% end %} end { {% for type, i in types %} %array{i}, {% end %} } end # require "/graph" # require "./graph/edge" struct WeightedEdge(T) include Comparable(WeightedEdge(T)) property to : Int32, cost : T def initialize(@to, @cost : T) end def <=>(other : WeightedEdge(T)) {cost, to} <=> {other.cost, other.to} end def to_s(io) : Nil io << '(' << to << ", " << cost << ')' end def inspect(io) : Nil io << "->#{to}(#{cost})" end end struct WeightedEdge2(T) include Comparable(WeightedEdge2(T)) property from : Int32, to : Int32, cost : T def initialize(@from, @to, @cost : T) end def initialize(@from, edge : WeightedEdge(T)) @to, @cost = edge.to, edge.cost end def <=>(other : WeightedEdge2(T)) {cost, from, to} <=> {other.cost, other.from, other.to} end def reverse WeightedEdge2(T).new(to, from, cost) end def sort WeightedEdge2(T).new(*{to, from}.minmax, cost) end def to_s(io) : Nil io << '(' << from << ", " << to << ", " << cost << ')' end def inspect(io) : Nil io << from << "->" << to << '(' << cost << ')' end end struct UnweightedEdge property to : Int32 def initialize(@to) end def cost 1 end def to_s(io) : Nil io << to end def inspect(io) : Nil io << "->" << to end end struct UnweightedEdge2 property from : Int32, to : Int32 def initialize(@from, @to) end def initialize(@from, edge : UnweightedEdge) @to = edge.to end def cost 1 end def reverse UnweightedEdge2.new(to, from) end def sort UnweightedEdge2.new(*{to, from}.minmax) end def to_s(io) : Nil io << '(' << from << ", " << to << ')' end def inspect(io) : Nil io << from << "->" << to end end module Graph(Edge, Edge2) include Enumerable(Edge2) getter graph : Array(Array(Edge)) def initialize(size : Int) @graph = Array(Array(Edge)).new(size) { [] of Edge } end def initialize(size : Int, edges : Enumerable) initialize(size) add_edges(edges) end # Add *edge*. abstract def <<(edge : Edge2) # :ditto: def <<(edge : Tuple) self << Edge2.new(*edge) end def add_edges(edges : Enumerable) edges.each { |edge| self << edge } end delegate size, to: @graph delegate :[], to: @graph def each : Nil (0...size).each do |v| self[v].each do |edge| yield Edge2.new(v, edge) end end end def reverse if self.class.directed? each_with_object(self.class.new(size)) do |edge, reversed| reversed << edge.reverse end else dup end end def to_undirected if self.class.directed? each_with_object(self.class.new(size)) do |edge, graph| graph << edge graph << edge.reverse if self.class.directed? end else dup end end def to_s(io : IO) : Nil io << '[' join(", ", io) do |edge, io| edge.inspect io end io << ']' end def inspect(io : IO) : Nil to_s(io) end end class DirectedGraph(T) include Graph(WeightedEdge(T), WeightedEdge2(T)) def initialize(size : Int) super end def initialize(size : Int, edges : Enumerable(WeightedEdge2(T))) super end def initialize(size : Int, edges : Enumerable({Int32, Int32, T})) super end def <<(edge : WeightedEdge2(T)) raise IndexError.new unless 0 <= edge.from < size && 0 <= edge.to < size @graph[edge.from] << WeightedEdge.new(edge.to, edge.cost) self end def self.weighted? true end def self.directed? true end end class UndirectedGraph(T) include Graph(WeightedEdge(T), WeightedEdge2(T)) def initialize(size : Int) super end def initialize(size : Int, edges : Enumerable(WeightedEdge2(T))) super end def initialize(size : Int, edges : Enumerable({Int32, Int32, T})) super end def <<(edge : WeightedEdge2(T)) raise IndexError.new unless 0 <= edge.from < size && 0 <= edge.to < size @graph[edge.from] << WeightedEdge.new(edge.to, edge.cost) @graph[edge.to] << WeightedEdge.new(edge.from, edge.cost) self end def self.weighted? true end def self.directed? false end end class UnweightedDirectedGraph include Graph(UnweightedEdge, UnweightedEdge2) def initialize(size : Int) super end def initialize(size : Int, edges : Enumerable) super end def <<(edge : UnweightedEdge2) raise IndexError.new unless 0 <= edge.from < size && 0 <= edge.to < size @graph[edge.from] << UnweightedEdge.new(edge.to) self end def self.weighted? false end def self.directed? true end end class UnweightedUndirectedGraph include Graph(UnweightedEdge, UnweightedEdge2) def initialize(size : Int) super end def initialize(size : Int, edges : Enumerable) super end def <<(edge : UnweightedEdge2) raise IndexError.new unless 0 <= edge.from < size && 0 <= edge.to < size @graph[edge.from] << UnweightedEdge.new(edge.to) @graph[edge.to] << UnweightedEdge.new(edge.from) self end def each_child(vertex : Int, parent, &block) : Nil graph[vertex].each do |u| yield u if u != parent end end def each_child(vertex : Int, parent) graph[vertex].each.select { |u| u != parent } end def self.weighted? false end def self.directed? false end end # require "/graph/re_rooting" # require "../graph" # Example of T: # ``` # struct DP # getter val : Int64, cnt : Int32 # # def initialize # @val, @cnt = 0i64, 0 # end # # def initialize(@val, @cnt) # end # # def +(other : self) : self # DP.new(val + other.val, cnt + other.cnt) # end # # def add_root(v : Int32) : self # DP.new(val + cnt, cnt + 1) # end # end # ``` class ReRooting(T, GraphType) getter graph : GraphType def initialize(size : Int) @graph = GraphType.new(size) @dp = Array(Array(T)).new @result = Array(T).new end def initialize(@graph : GraphType) @dp = Array(Array(T)).new @result = Array(T).new end delegate size, to: @graph delegate :<<, to: @graph delegate add_edges, to: @graph private def dfs(v : Int32, p : Int32) : T graph[v].each_with_index.select { |(edge, i)| edge.to != p }.reduce(T.new) { |acc, (edge, i)| acc + (@dp[v][i] = dfs(edge.to, v)) }.add_root(v) end private def bfs(v : Int32, p : Int32, dp_par : T) : Nil graph[v].each_with_index do |edge, i| @dp[v][i] = dp_par if edge.to == p end n = graph[v].size dp_left = Array.new(n + 1, T.new) (0...n).each do |i| dp_left[i + 1] = dp_left[i] + @dp[v][i] end dp_right = Array.new(n + 1, T.new) (0...n).reverse_each do |i| dp_right[i] = dp_right[i + 1] + @dp[v][i] end @result[v] = dp_left.last.add_root(v) graph[v].each_with_index do |edge, i| bfs(edge.to, v, (dp_left[i] + dp_right[i + 1]).add_root(v)) if edge.to != p end end def solve : Array(T) @dp = Array.new(size) { |i| Array.new(@graph[i].size, T.new) } @result = Array.new(size, T.new) dfs(0, -1) bfs(0, -1, T.new) @result end end # require "/graph/decompose" # require "../graph" # require "../datastructure/union_find" class UnionFind @d : Array(Int32) def initialize(n : Int) @d = Array.new(n, -1) end def initialize(n : Int, edges : Enumerable({Int32, Int32})) initialize(n) edges.each { |u, v| unite(u, v) } end def root(x : Int) @d[x] < 0 ? x : (@d[x] = root(@d[x])) end def unite(x : Int, y : Int) x = root(x) y = root(y) return false if x == y x, y = y, x if @d[x] > @d[y] @d[x] += @d[y] @d[y] = x true end def same?(x : Int, y : Int) root(x) == root(y) end def size(x : Int) -@d[root(x)] end def groups groups = Hash(Int32, Set(Int32)).new { |h, k| h[k] = Set(Int32).new } @d.size.times do |i| groups[root(i)] << i end groups.values.to_set end end module Graph(Edge, Edge2) def decompose : {Array(self), Array({Int32, Int32})} uf = UnionFind.new(size) each do |edge| uf.unite(edge.from, edge.to) end groups = uf.groups.to_a index = Array.new(size, {-1, -1}) groups.each_with_index do |group, i| group.each_with_index do |v, j| index[v] = {i, j} end end graphs = Array.new(groups.size) { |i| self.class.new(groups[i].size) } if self.class.directed? each do |edge| i1, j1 = index[edge.from] _, j2 = index[edge.to] graphs[i1] << {j1, j2} end else edge_set = Set(Edge2).new each do |edge| if edge_set.add?(edge.sort) i1, j1 = index[edge.from] _, j2 = index[edge.to] graphs[i1] << {j1, j2} end end end {graphs, index} end end # require "/graph/lca" # require "../graph" class LCA(Edge, Edge2) getter graph : Graph(Edge, Edge2) getter depth : Array(Int32) private def dfs(vertex : Int, par : Int, dep : Int) : Nil @parent[0][vertex] = par @depth[vertex] = dep @graph[vertex].each do |edge| dfs(edge.to, vertex, dep + 1) if edge.to != par end end def initialize(@graph : Graph(Edge, Edge2), root : Int) @log2 = Math.log2(size).to_i.succ.as(Int32) @depth = Array(Int32).new(size, -1) @parent = Array(Array(Int32)).new(@log2) { Array.new(size, 0) } dfs(root, -1, 0) (0...@log2 - 1).each do |k| (0...size).each do |v| if @parent[k][v] < 0 @parent[k + 1][v] = -1 else @parent[k + 1][v] = @parent[k][@parent[k][v]] end end end end delegate size, to: @graph def lca(u : Int, v : Int) : Int32 raise IndexError.new unless 0 <= u < size raise IndexError.new unless 0 <= v < size u, v = v, u if @depth[u] > @depth[v] (0...@log2).each do |k| v = @parent[k][v] if (@depth[v] - @depth[u]).bit(k) == 1 end return u if u == v (0...@log2).reverse_each do |k| u, v = @parent[k][u], @parent[k][v] if @parent[k][u] != @parent[k][v] end @parent[0][u] end def dist(u : Int, v : Int) : Int32 @depth[u] + @depth[v] - @depth[lca(u, v)] * 2 end end struct DP getter sum : Int64, cnt : Int32 class_property! k : Array(Int32) def initialize @sum, @cnt = 0i64, 0 end def initialize(@sum, @cnt) end def +(other : self) : self DP.new(sum + other.sum, cnt + other.cnt) end def add_root(v : Int32) : self DP.new(sum + cnt, cnt + DP.k[v]) end end n, m, q = input(i, i, i) g = UnweightedUndirectedGraph.new n, input({i - 1, i - 1}[m]) graphs, index = g.decompose lcas = graphs.map { |graph| LCA.new(graph, 0) } cnts = Array.new(graphs.size) { |i| Array.new(graphs[i].size, 0) } ans = 0i64 q.times do a, b = input(i - 1, i - 1) ai, aj = index[a] bi, bj = index[b] if ai == bi ans += lcas[ai].dist(aj, bj) else cnts[ai][aj] += 1 cnts[bi][bj] += 1 end end graphs.each_with_index do |graph, i| DP.k = cnts[i] dp = ReRooting(DP, UnweightedUndirectedGraph).new(graph) ans += dp.solve.min_of(&.sum) end puts ans