module main; // https://yukicoder.me/submissions/632230 より // 燃やす埋める、最大フロー import std; // https://ei1333.github.io/library/graph/flow/dinic.hpp より struct Dinic(Flow) { immutable Flow INF; struct Edge { int to; Flow cap; int rev; bool isRev; int idx; } Edge[][] graph; int[] minCost, iter; // コンストラクタ this(int V) { INF = Flow.max; graph.length = V; } void addEdge(int from ,int to, Flow cap, int idx = -1) { graph[from] ~= Edge(to, cap, graph[to].length.to!int, false, idx); graph[to] ~= Edge(from, 0, graph[from].length.to!int, true, idx); } bool buildAugmentPath(int s, int t) { minCost = uninitializedArray!(int[])(graph.length); minCost[] = -1; minCost[s] = 0; auto que = DList!int(s); while (!que.empty && minCost[t] == -1) { int p = que.front; que.removeFront; foreach (e; graph[p]) { if (e.cap <= 0 || minCost[e.to] != -1) continue; minCost[e.to] = minCost[p] + 1; que.insertBack(e.to); } } return minCost[t] != -1; } Flow findMinDistAugmentPath(int idx, in int t, Flow flow) { if (idx == t) return flow; for (int* i = &iter[idx]; *i < graph[idx].length; (*i)++) { Edge* e = &graph[idx][*i]; if (e.cap <= 0 || minCost[idx] >= minCost[e.to]) continue; Flow d = findMinDistAugmentPath(e.to, t, min(flow, e.cap)); if (d > 0) { e.cap -= d; graph[e.to][e.rev].cap += d; return d; } } return 0; } Flow maxFlow(int s, int t) { Flow flow = 0; while (buildAugmentPath(s, t)) { iter = new int[](graph.length); Flow f; while ((f = findMinDistAugmentPath(s, t, INF)) > 0) flow += f; } return flow; } void output() { foreach (i; 0 .. graph.length) { foreach (e; graph[i]) { if (e.isRev) continue; auto revE = graph[e.to][e.rev]; writefln("%d->%d (flow: %d/%d)", i, e.to, revE.cap, e.cap + revE.cap); } } } bool[] minCut(int s) { auto used = new bool[](graph.length); used[s] = true; auto que = DList!int(s); while (!que.empty) { int p = que.front; que.removeFront; foreach (e; graph[p]) { if (e.cap <= 0 || used[e.to]) continue; used[e.to] = true; que.insertBack(e.to); } } return used; } } void main() { // 入力 int N = readln.chomp.to!int; auto flow = Dinic!int(2 * N + 2); const src = 2 * N, sink = 2 * N + 1; int res = 0; foreach (i; 0 .. N) { int b, c; readln.chomp.formattedRead("%d %d", b, c); res += b + c; flow.addEdge(src, i, c); flow.addEdge(i, i + N, b + c); flow.addEdge(i + N, sink, b); } int M = readln.chomp.to!int; foreach (_; 0 .. M) { int u, v; readln.chomp.formattedRead("%d %d", u, v); flow.addEdge(v + N, u, flow.INF); } // 答えの計算と出力 writeln(res - flow.maxFlow(src, sink)); }