module Graphical
    require 'set'
 
    def get_path_by_bfs(s, t)
        prev_node = {}
        reached = Set[s]
        queue = [s]
        while !queue.empty? 
            u = queue.shift
            each_out_connection_of(u){|v, _|
                next if reached.include?(v) 
                reached << v
                queue << v
                prev_node[v] = u
 
                if v == t
                    path = [v]
                    while v = prev_node[v]
                        path.unshift v
                    end
                    return path
                end
            }
        end 
        return nil
    end
 
    def get_path_by_dfs(s, t, reached = Set.new)
        reached << s
        return [s] if s == t
        each_out_connection_of(s){|v|
            next if reached.include?(v)
            path = get_path_by_dfs(v, t, reached) 
            return [s] + path if path
        }
        nil
    end
 
    def reachable_from(s, max_depth = nil)
        reached = Set[s]
        queue = [s]
        depth = 0
        loop {
            break if max_depth && depth >= max_depth
            next_queue = []
            until queue.empty?
                u = queue.shift
                each_out_connection_of(u){|v, _|
                    next if reached.include?(v)
                    reached << v
                    next_queue << v
                }
            end
            break if next_queue.empty?
            queue = next_queue
            depth += 1
        }
        return reached
    end
 
    def bfs(start)
        raise "start must be Enumerable" if !start.kind_of?(Enumerable)
        reached = Set[*start.to_a]
        queue = []
        start.each{|s| queue << s}
        dist = {}
        loop.with_index {|_, depth|
            next_queue = []
            until queue.empty?
                u = queue.shift
                return depth if block_given? && yield(u, depth)
                dist[u] = depth
                each_out_connection_of(u){|v, _|
                    next if reached.include?(v)
                    reached << v
                    next_queue << v
                }
            end
            break if next_queue.empty?
            queue = next_queue
        }
        block_given? ? nil : dist
    end
 
    def dijkstra(start)
        raise "start must be Enumerable" if !start.kind_of?(Enumerable)
        h = Heap.new
        reached = Set[*start.to_a]
        start.each{|s| h.add(s, 0)}
 
        dist = {}
        until h.empty?
            u, key = h.del_min
            return key if block_given? && yield(u, key)
            dist[u] = key
            each_out_connection_of(u){|v, l|
                d = dist[u] + l
                if reached.include?(v)
                    h.update_key(v, d)
                else
                    h.add(v, d)
                    reached << v
                end
            }
        end
        block_given? ? nil : dist
    end
 
    def bidir_dijkstra(s, t)
        f_dist = {}
        b_dist = {}
 
        f_heap = Heap.new
        b_heap = Heap.new
 
        f_heap.add(s, 0)
        b_heap.add(t, 0)
 
        f_reached = Set[s]
        b_reached = Set[t]
 
        f_current_dist = b_current_dist = 0
        best = Float::INFINITY
 
        loop {
            if !f_heap.empty?
                u, key = f_heap.del_min
                f_dist[u] = key
                f_current_dist = key
                each_out_connection_of(u){|v, l|
                    d = f_dist[u] + l
                    if b_dist[v]
                        path_len = d + b_dist[v]
                        best = path_len if path_len < best
                    end
                    if f_reached.include?(v)
                        f_heap.update_key(v, d)
                    else
                        f_heap.add(v, d)
                        f_reached << v
                    end
                }
            end
 
            if !b_heap.empty?
                u, key = b_heap.del_min
                b_dist[u] = key
                b_current_dist = key
                each_in_connection_of(u){|v, l|
                    d = b_dist[u] + l
                    if f_dist[v]
                        path_len = d + f_dist[v]
                        best = path_len if path_len < best
                    end
                    if b_reached.include?(v)
                        b_heap.update_key(v, d)
                    else
                        b_heap.add(v, d)
                        b_reached << v
                    end
                }
            end
 
            return best if f_current_dist + b_current_dist >= best
            return nil if f_heap.empty? && b_heap.empty?
        }
    end
 
    def a_star(start)
        raise "a_star need termination condition" unless block_given?
        h = Heap.new
        reached = Set[start]
        h.add(start, [a_star_heuristic(start), 0])
 
        dist = {}
        until h.empty?
            u, (e, d) = h.del_min
            return d if yield(u, dist)
            dist[u] = d
            each_out_connection_of(u){|v, l|
                d = dist[u] + l
                e = d + a_star_heuristic(v)
                if reached.include?(v)
                    h.update_key(v, [e, d])
                else
                    h.add(v, [e, d])
                    reached << v
                end
            }
        end
        block_given? ? nil : dist
    end
 
    #make_variations :bidir_dijkstra
 
    def prim(start)
        h = Heap.new
        h.add(start, 0)
        reached = Set[start]
        tree_len = 0
 
        until h.empty?
            u, key = h.del_min
            tree_len += key
 
            each_connection_of(u){|v, d|
                if reached.include?(v)
                    h.update_key(v, d)
                else
                    h.add(v, d)
                    reached << v
                end
            }
        end
        tree_len
    end
 
    def each_layer_from(start)
        raise "start must be Enumerable" if !start.kind_of?(Enumerable)
        return enum_for(__method__, start) unless block_given?
        reached = Set[*start]
        current_layer = start
 
        loop {
            yield current_layer
            next_layer = []
            current_layer.each{|u|
                each_out_connection_of(u){|v|
                    next if reached.include?(v)
                    reached << v
                    next_layer << v
                }
            }   
 
            return if next_layer.empty?
            current_layer = next_layer
        }
    end
end
 
class Graph
    include Graphical
 
    def initialize(*options)
        @options = Set[*options]
    end
 
    def add_node(property = {})
        Node.new(property)
    end
 
    def add_edge(u, v, property = {})
        e = Edge.new(u, v, property)
        u.add_edge(e)
        v.add_edge(e)
        e
    end
     
    def del_edge(e)
        u, v = e.opposite.keys
        u.del_edge(e)
        v.del_edge(e)
        e
    end
 
    class Node
        def initialize(property)
            @property = property
            @edges = Set.new
        end
 
        def add_edge(e)
            @edges << e
        end
 
        def del_edge(e)
            @edges.delete(e)
        end
 
        def to_s
            @property[:name] || super
        end
 
        def each_edge
            @edges.each{|e| 
                yield e
            }
        end
 
        attr_reader :property
    end
 
    class Edge
        def initialize(u, v, property)
            @opposite = {u => v, v => u}
            @property = property
        end
        attr_reader :opposite, :property
 
        def to_s
            @property[:name] || super
        end
 
        def length
            @property[:length] || 1
        end
    end
 
    def each_out_connection_of(u)
        u.each_edge{|e|
            yield(e.opposite[u], e.length)
        }
    end
 
    alias :each_in_connection_of :each_out_connection_of
end
 
h, w, k = gets.split.map &:to_i
a = (1..h).map{ gets.chomp.split("") }
 
time_cost = (1..h).map{gets.split.map &:to_i}
on_cost = (1..h).map{gets.split.map &:to_i}
off_cost = (1..h).map{gets.split.map &:to_i}
tasks = (1..k).map{gets.split.map &:to_i}
 
g = Graph.new
nodes = (0..h-1).map{|i| (0..w-1).map{|j|
    g.add_node({
        :y => i,
        :x => j,
        :prev_visit => 0,
        :on_best => Float::INFINITY,
        :off_best => 0
    })
}}
(0..h-1).each{|i|
    (0..w-1).each{|j|
        g.add_edge(nodes[i-1][j], nodes[i][j]) if i > 0 && a[i-1][j] == a[i][j]
        g.add_edge(nodes[i][j-1], nodes[i][j]) if j > 0 && a[i][j-1] == a[i][j]
    }
}
 
i, j = tasks.shift
u = nodes[i][j]
u.property[:on_best] = on_cost[i][j]
u.property[:off_best] = on_cost[i][j] + off_cost[i][j]
t = 0
 
until tasks.empty?
    i, j = tasks.shift
    v = nodes[i][j]
    path = g.get_path_by_bfs(u, v)
    path.shift
    path.each{|w|
        t += 1
        x, y = w.property[:x], w.property[:y]
        c = [
            w.property[:off_best] + on_cost[y][x],
            w.property[:on_best] + (t - w.property[:prev_visit]) * time_cost[y][x]
        ].min
        w.property[:off_best] = c + off_cost[y][x]
        w.property[:on_best] = c
        w.property[:prev_visit] = t
    }
    u = v
end
 
p nodes.flatten.map{|v|
    v.property[:off_best]
}.inject(:+)

Measured memory_bytes: 14656