Problem:
Score : 1200 points

Problem Statement

Snuke is playing with red and blue balls, placing them on a two-dimensional plane.

First, he performed N operations to place red balls. In the i-th of these operations, he placed RC_i red balls at coordinates (RX_i,RY_i).
Then, he performed another N operations to place blue balls. In the i-th of these operations, he placed BC_i blue balls at coordinates (BX_i,BY_i).
The total number of red balls placed and the total number of blue balls placed are equal, that is, \sum_{i=1}^{N} RC_i = \sum_{i=1}^{N} BC_i. Let this value be S.

Snuke will now form S pairs of red and blue balls so that every ball belongs to exactly one pair.
Let us define the score of a pair of a red ball at coordinates (rx, ry) and a blue ball at coordinates (bx, by) as |rx-bx| + |ry-by|.

Snuke wants to maximize the sum of the scores of the pairs.
Help him by finding the maximum possible sum of the scores of the pairs.

Constraints

1 \leq N \leq 1000

0 \leq RX_i,RY_i,BX_i,BY_i \leq 10^9

1 \leq RC_i,BC_i \leq 10

\sum_{i=1}^{N} RC_i = \sum_{i=1}^{N} BC_i

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
RX_1 RY_1 RC_1
RX_2 RY_2 RC_2
\vdots
RX_N RY_N RC_N
BX_1 BY_1 BC_1
BX_2 BY_2 BC_2
\vdots
BX_N BY_N BC_N

Output

Print the maximum possible sum of the scores of the pairs.

Sample Input 1

2
0 0 1
3 2 1
2 2 1
5 0 1

Sample Output 1

8

If we pair the red ball at coordinates (0,0) and the blue ball at coordinates (2,2), the score of this pair is |0-2| + |0-2|=4.
Then, if we pair the red ball at coordinates (3,2) and the blue ball at coordinates (5,0), the score of this pair is |3-5| + |2-0|=4.
Making these two pairs results in the total score of 8, which is the maximum result.

Sample Input 2

3
0 0 1
2 2 1
0 0 2
1 1 1
1 1 1
3 3 2

Sample Output 2

16

Snuke may have performed multiple operations at the same coordinates.

Sample Input 3

10
582463373 690528069 8
621230322 318051944 4
356524296 974059503 6
372751381 111542460 9
392867214 581476334 6
606955458 513028121 5
882201596 791660614 9
250465517 91918758 3
618624774 406956634 6
426294747 736401096 5
974896051 888765942 5
726682138 336960821 3
715144179 82444709 6
599055841 501257806 6
390484433 962747856 4
912334580 219343832 8
570458984 648862300 6
638017635 572157978 10
435958984 585073520 7
445612658 234265014 6

Sample Output 3

45152033546

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Time Limit Exceeded)

import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.util.Comparator;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskD solver = new TaskD();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskD {
        static List<TaskD.Vertex> all = new ArrayList<>();
        static final long INF = (long) 1e18;

        void addEdge(TaskD.Vertex a, TaskD.Vertex b, long cap, long rcap, long cost) {
            TaskD.Edge ab = new TaskD.Edge(a, b, cap, cost);
            TaskD.Edge ba = new TaskD.Edge(b, a, rcap, -cost);
            ab.rev = ba;
            ba.rev = ab;
            a.outgo.add(ab);
            b.outgo.add(ba);
        }

        private void heapUp(TaskD.Vertex[] heap, int at) {
            while (at > 0) {
                int i = (at - 1) / 2;
                if (heap[i].dist <= heap[at].dist) break;
                TaskD.Vertex tmp = heap[at];
                heap[at] = heap[i];
                heap[i] = tmp;
                heap[at].heapIndex = at;
                heap[i].heapIndex = i;
                at = i;
            }
        }

        private void heapDown(TaskD.Vertex[] heap, int at, int nheap) {
            while (true) {
                int i = at;
                if (2 * at + 1 < nheap && heap[2 * at + 1].dist < heap[i].dist) i = 2 * at + 1;
                if (2 * at + 2 < nheap && heap[2 * at + 2].dist < heap[i].dist) i = 2 * at + 2;
                if (i == at) break;
                TaskD.Vertex tmp = heap[at];
                heap[at] = heap[i];
                heap[i] = tmp;
                heap[at].heapIndex = at;
                heap[i].heapIndex = i;
                at = i;
            }
        }

        private long minCostMaxFlow(TaskD.Vertex s, TaskD.Vertex t) {
            long res = 0;
            for (TaskD.Vertex v : all) v.dist = INF;
            s.dist = 0;
            while (true) {
                boolean updated = false;
                for (TaskD.Vertex v : all)
                    if (v.dist < INF) {
                        for (TaskD.Edge e : v.outgo) {
                            if (e.cap > 0) {
                                if (e.dest.dist > v.dist + e.cost) {
                                    e.dest.dist = v.dist + e.cost;
                                    updated = true;
                                }
                            }
                        }
                    }
                if (!updated) break;
            }
            long maxDist = 0;
            for (TaskD.Vertex v : all) if (v.dist < INF && v.dist > maxDist) maxDist = v.dist;
            for (TaskD.Vertex v : all) v.phi = v.dist < INF ? v.dist : maxDist;
            TaskD.Vertex[] heap = new TaskD.Vertex[all.size()];
            int nheap = 0;
            while (true) {
                for (TaskD.Vertex v : all) v.dist = INF;
                s.dist = 0;
                nheap = 1;
                heap[0] = s;
                s.heapIndex = 0;
                while (nheap > 0) {
                    TaskD.Vertex bi = heap[0];
                    bi.heapIndex = -1;
                    if (nheap > 1) {
                        heap[0] = heap[nheap - 1];
                        heap[0].heapIndex = 0;
                    }
                    --nheap;
                    if (nheap > 0) {
                        heapDown(heap, 0, nheap);
                    }
                    for (TaskD.Edge e : bi.outgo)
                        if (e.cap > 0) {
                            long edge = bi.phi - e.dest.phi + e.cost;
                            if (edge < 0) {
                                throw new RuntimeException();
                            }
                            if (e.dest.dist > bi.dist + edge) {
                                e.dest.dist = bi.dist + edge;
                                e.dest.prev = e;
                                if (e.dest.heapIndex < 0) {
                                    e.dest.heapIndex = nheap;
                                    heap[nheap++] = e.dest;
                                    heapUp(heap, nheap - 1);
                                } else {
                                    heapUp(heap, e.dest.heapIndex);
                                }
                            }
                        }
                }
                if (t.dist >= INF) break;
                res += t.dist - s.phi + t.phi;
                TaskD.Vertex at = t;
                while (at != s) {
                    --at.prev.cap;
                    ++at.prev.rev.cap;
                    at = at.prev.rev.dest;
                }
                maxDist = 0;
                for (TaskD.Vertex v : all) if (v.dist < INF && v.dist > maxDist) maxDist = v.dist;
                for (TaskD.Vertex v : all) v.phi += v.dist < INF ? v.dist : maxDist;
            }
            return res;
        }

        public void solve(int testNumber, InputReader in, PrintWriter out) {
            int n = in.nextInt();
            TaskD.Ball[] balls = new TaskD.Ball[2 * n];
            long totalAmount = 0;
            for (int i = 0; i < 2 * n; ++i) {
                balls[i] = new TaskD.Ball();
                balls[i].x = in.nextInt();
                balls[i].y = in.nextInt();
                balls[i].amount = in.nextInt();
                balls[i].source = i < n;
                if (balls[i].source) totalAmount += balls[i].amount;
            }
            n *= 2;
            TaskD.Vertex s = new TaskD.Vertex();
            TaskD.Vertex t = new TaskD.Vertex();
            for (int i = 0; i < n; ++i) {
                balls[i].v = new TaskD.Vertex();
                if (balls[i].source) {
                    addEdge(s, balls[i].v, balls[i].amount, 0, 0);
                } else {
                    addEdge(balls[i].v, t, balls[i].amount, 0, 0);
                }
            }
            for (int sx = -1; sx <= 1; sx += 2) {
                for (int sy = -1; sy <= 1; sy += 2) {
                    for (TaskD.Ball b : balls) {
                        b.position = b.x * sx + b.y * sy;
                    }
                    Arrays.sort(balls, new Comparator<TaskD.Ball>() {

                        public int compare(TaskD.Ball o1, TaskD.Ball o2) {
                            return Long.compare(o1.position, o2.position);
                        }
                    });
                    TaskD.Vertex prev = null;
                    long prevPosition = -1;
                    for (int i = 0; i < balls.length; ) {
                        int j = i;
                        while (j < balls.length && balls[j].position == balls[i].position) ++j;

                        TaskD.Vertex cur = new TaskD.Vertex();
                        long curPosition = balls[i].position;
                        if (prev != null) {
                            addEdge(prev, cur, totalAmount, 0, prevPosition - curPosition);
                        }
                        for (int k = i; k < j; ++k) {
                            if (balls[k].source) {
                                addEdge(balls[k].v, cur, totalAmount, 0, 0);
                            } else {
                                addEdge(cur, balls[k].v, totalAmount, 0, 0);
                            }
                        }

                        prev = cur;
                        prevPosition = curPosition;
                        i = j;
                    }
                }
            }
            long res = -minCostMaxFlow(s, t);
            out.println(res);
        }

        static class Edge {
            TaskD.Vertex src;
            TaskD.Vertex dest;
            long cap;
            long cost;
            TaskD.Edge rev;

            public Edge(TaskD.Vertex src, TaskD.Vertex dest, long cap, long cost) {
                this.src = src;
                this.dest = dest;
                this.cap = cap;
                this.cost = cost;
            }

        }

        static class Vertex {
            long phi = 0;
            long dist;
            int heapIndex = -1;
            TaskD.Edge prev;
            List<TaskD.Edge> outgo = new ArrayList<>();

            public Vertex() {
                all.add(this);
            }

        }

        static class Ball {
            int x;
            int y;
            int amount;
            long position;
            boolean source;
            TaskD.Vertex v;

        }

    }

    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

    }
}