import java.io.OutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.Arrays; import java.io.BufferedWriter; import java.util.InputMismatchException; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; import java.io.Writer; import java.io.OutputStreamWriter; import java.io.InputStream; /** * Built using CHelper plug-in * Actual solution is at the top */ public class MaximumFlow_lewin { public static void main(String[] args) { InputStream inputStream = System.in; OutputStream outputStream = System.out; InputReader in = new InputReader(inputStream); OutputWriter out = new OutputWriter(outputStream); MaximumFlow solver = new MaximumFlow(); solver.solve(1, in, out); out.close(); } static class MaximumFlow { public int LOG = 6; public long INF = 1L << 50; public void solve(int testNumber, InputReader in, OutputWriter out) { int n = in.nextInt(), m = in.nextInt(), k = in.nextInt(); int[][] arr = new int[n][m]; for (int i = 0; i < n; i++) arr[i] = in.readIntArray(m); int nnodes = (n * m + 1) * LOG * LOG + k + 2; List[] gg = Stream.generate(ArrayList::new).limit(nnodes).toArray(List[]::new); for (int i = 0; i < k; i++) { int x1 = in.nextInt() - 1, x2 = in.nextInt() - 1, y1 = in.nextInt() - 1, y2 = in.nextInt() - 1; int cap = in.nextInt(); MaxFlowLong.addEdge(gg, nnodes - 1, i, cap); while (y1 <= y2) { int tx1 = x1, tx2 = x2; int hy = Integer.highestOneBit(y2 - y1 + 1); int gy = Integer.numberOfTrailingZeros(hy); while (tx1 <= tx2) { int hx = Integer.highestOneBit(tx2 - tx1 + 1); int gx = Integer.numberOfTrailingZeros(hx); MaxFlowLong.addEdge( gg, i, (tx1 * m + y1) * LOG * LOG + gx * LOG + gy + k, INF ); tx1 += 1 << gx; } y1 += 1 << gy; } } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { MaxFlowLong.addEdge( gg, (i * m + j) * LOG * LOG + k, nnodes - 2, arr[i][j] ); for (int k1 = 1; k1 < LOG; k1++) { for (int k2 = 0; k2 < LOG; k2++) { MaxFlowLong.addEdge( gg, (i * m + j) * LOG * LOG + k1 * LOG + k2 + k, (i * m + j) * LOG * LOG + (k1 - 1) * LOG + k2 + k, INF ); if (i + (1 << (k1 - 1)) < n) MaxFlowLong.addEdge( gg, (i * m + j) * LOG * LOG + k1 * LOG + k2 + k, ((i + (1 << (k1 - 1))) * m + j) * LOG * LOG + (k1 - 1) * LOG + k2 + k, INF ); } } for (int k2 = 1; k2 < LOG; k2++) { MaxFlowLong.addEdge( gg, (i * m + j) * LOG * LOG + k2 + k, (i * m + j) * LOG * LOG + (k2 - 1) + k, INF ); if (j + (1 << (k2 - 1)) < m) MaxFlowLong.addEdge( gg, (i * m + j) * LOG * LOG + k2 + k, (i * m + (j + (1 << (k2 - 1)))) * LOG * LOG + (k2 - 1) + k, INF ); } } } out.println(MaxFlowLong.maxFlow(gg, nnodes - 1, nnodes - 2)); } } static class InputReader { private InputStream stream; private byte[] buf = new byte[1024]; private int curChar; private int numChars; public InputReader(InputStream stream) { this.stream = stream; } public int[] readIntArray(int tokens) { int[] ret = new int[tokens]; for (int i = 0; i < tokens; i++) { ret[i] = nextInt(); } return ret; } public int read() { if (this.numChars == -1) { throw new InputMismatchException(); } else { if (this.curChar >= this.numChars) { this.curChar = 0; try { this.numChars = this.stream.read(this.buf); } catch (IOException var2) { throw new InputMismatchException(); } if (this.numChars <= 0) { return -1; } } return this.buf[this.curChar++]; } } public int nextInt() { int c; for (c = this.read(); isSpaceChar(c); c = this.read()) { ; } byte sgn = 1; if (c == 45) { sgn = -1; c = this.read(); } int res = 0; while (c >= 48 && c <= 57) { res *= 10; res += c - 48; c = this.read(); if (isSpaceChar(c)) { return res * sgn; } } throw new InputMismatchException(); } public static boolean isSpaceChar(int c) { return c == 32 || c == 10 || c == 13 || c == 9 || c == -1; } } static class MaxFlowLong { public static void addEdge(List[] graph, int s, int t, long cap) { graph[s].add(new MaxFlowLong.Edge(t, graph[t].size(), cap)); graph[t].add(new MaxFlowLong.Edge(s, graph[s].size() - 1, 0)); } static boolean dinicBfs(List[] graph, int src, int dest, int[] dist) { Arrays.fill(dist, -1); dist[src] = 0; int[] Q = new int[graph.length]; int sizeQ = 0; Q[sizeQ++] = src; for (int i = 0; i < sizeQ; i++) { int u = Q[i]; for (MaxFlowLong.Edge e : graph[u]) { if (dist[e.t] < 0 && e.f < e.cap) { dist[e.t] = dist[u] + 1; Q[sizeQ++] = e.t; } } } return dist[dest] >= 0; } static long dinicDfs(List[] graph, int[] ptr, int[] dist, int dest, int u, long f) { if (u == dest) return f; for (; ptr[u] < graph[u].size(); ++ptr[u]) { MaxFlowLong.Edge e = graph[u].get(ptr[u]); if (dist[e.t] == dist[u] + 1 && e.f < e.cap) { long df = dinicDfs(graph, ptr, dist, dest, e.t, Math.min(f, e.cap - e.f)); if (df > 0) { e.f += df; graph[e.t].get(e.rev).f -= df; return df; } } } return 0; } public static long maxFlow(List[] graph, int src, int dest) { long flow = 0; int[] dist = new int[graph.length]; while (dinicBfs(graph, src, dest, dist)) { int[] ptr = new int[graph.length]; while (true) { long df = dinicDfs(graph, ptr, dist, dest, src, Integer.MAX_VALUE); if (df == 0) break; flow += df; } } return flow; } public static class Edge { int t; int rev; long cap; long f; public Edge(int t, int rev, long cap) { this.t = t; this.rev = rev; this.cap = cap; } } } static class OutputWriter { private final PrintWriter writer; public OutputWriter(OutputStream outputStream) { writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream))); } public OutputWriter(Writer writer) { this.writer = new PrintWriter(writer); } public void close() { writer.close(); } public void println(long i) { writer.println(i); } } }