#include <bits/stdc++.h>
using namespace std;
using lint = long long int;
using pint = pair<int, int>;
using plint = pair<lint, lint>;
struct fast_ios { fast_ios(){ cin.tie(0); ios::sync_with_stdio(false); cout << fixed << setprecision(20); }; } fast_ios_;
#define FOR(i, begin, end) for(int i=(begin),i##_end_=(end);i<i##_end_;i++)
#define IFOR(i, begin, end) for(int i=(end)-1,i##_begin_=(begin);i>=i##_begin_;i--)
#define REP(i, n) FOR(i,0,n)
#define IREP(i, n) IFOR(i,0,n)
template<typename T> istream &operator>>(istream &is, vector<T> &vec){ for (auto &v : vec) is >> v; return is; }
template<typename T> ostream &operator<<(ostream &os, const vector<T> &vec){ os << "["; for (auto v : vec) os << v << ","; os << "]"; return os; }
template<typename T> ostream &operator<<(ostream &os, const deque<T> &vec){ os << "deq["; for (auto v : vec) os << v << ","; os << "]"; return os; }
template<typename T> ostream &operator<<(ostream &os, const set<T> &vec){ os << "{"; for (auto v : vec) os << v << ","; os << "}"; return os; }
template<typename T> ostream &operator<<(ostream &os, const unordered_set<T> &vec){ os << "{"; for (auto v : vec) os << v << ","; os << "}"; return os; }
template<typename T> ostream &operator<<(ostream &os, const multiset<T> &vec){ os << "{"; for (auto v : vec) os << v << ","; os << "}"; return os; }
template<typename T> ostream &operator<<(ostream &os, const unordered_multiset<T> &vec){ os << "{"; for (auto v : vec) os << v << ","; os << "}"; return os; }
template<typename T1, typename T2> ostream &operator<<(ostream &os, const pair<T1, T2> &pa){ os << "(" << pa.first << "," << pa.second << ")"; return os; }
template<typename TK, typename TV> ostream &operator<<(ostream &os, const map<TK, TV> &mp){ os << "{"; for (auto v : mp) os << v.first << "=>" << v.second << ","; os << "}"; return os; }
template<typename TK, typename TV> ostream &operator<<(ostream &os, const unordered_map<TK, TV> &mp){ os << "{"; for (auto v : mp) os << v.first << "=>" << v.second << ","; os << "}"; return os; }
template<typename T> void ndarray(vector<T> &vec, int len) { vec.resize(len); }
template<typename T, typename... Args> void ndarray(vector<T> &vec, int len, Args... args) { vec.resize(len); for (auto &v : vec) ndarray(v, args...); }
template<typename T> bool mmax(T &m, const T q) { if (m < q) {m = q; return true;} else return false; }
template<typename T> bool mmin(T &m, const T q) { if (m > q) {m = q; return true;} else return false; }
template<typename T1, typename T2> pair<T1, T2> operator+(const pair<T1, T2> &l, const pair<T1, T2> &r) { return make_pair(l.first + r.first, l.second + r.second); }
template<typename T1, typename T2> pair<T1, T2> operator-(const pair<T1, T2> &l, const pair<T1, T2> &r) { return make_pair(l.first - r.first, l.second - r.second); }
#define dbg(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ") " << __FILE__ << endl;
#define FI first
#define SE second
#define ALL(x) (x).begin(), (x).end()
#define SZ(x) ((lint)(x).size())
#define POW2(n) (1LL << (n))


template <typename T>
class MinCostFlow
{
    struct edge
    {
        int to, rev;
        T cap, cost;
    };
    int V;
    std::vector<std::vector<edge> > G;
    std::vector<T> distance;
    std::vector<int> prevv, preve;

    std::vector<T> h;
    using P = std::pair<T, int>;

    T INF = std::numeric_limits<T>::max();

public:
    MinCostFlow(int N) : V(N),
                         G(std::vector<std::vector<edge> >(N)),
                         distance(std::vector<T>(N)),
                         prevv(std::vector<int>(N)),
                         preve(std::vector<int>(N)) {}
    
    void add_edge(int from, int to, T cap, T cost)
    {
        G[from].push_back((edge){to, (int)G[to].size(), cap, cost});
        G[to].push_back((edge){from, (int)G[from].size() - 1, (T)0, -cost});
    }

    // Bellman-Ford based, O(FVE)
    T mcfBellmanFord(int s, int t, T f)
    {
        T res = 0;
        while (f > 0)
        {
            distance = std::vector<T>(V, INF);
            distance[s] = (T)0;
            bool isUpdated = true;
            while (isUpdated)
            {
                isUpdated = false;
                for (int v = 0; v < V; v++)
                {
                    if (distance[v] == INF) continue;
                    for (unsigned i = 0; i < G[v].size(); i++)
                    {
                        edge &e = G[v][i];
                        if (e.cap > 0 && distance[e.to] > distance[v] + e.cost)
                        {
                            distance[e.to] = distance[v] + e.cost;
                            prevv[e.to] = v;
                            preve[e.to] = i;
                            isUpdated = true;
                        }
                    }
                }
            }

            if (distance[t] == INF)
            {
                return (T)(-1);
            }

            T d = f;
            for (int v = t; v != s; v = prevv[v])
            {
                d = std::min(d, G[prevv[v]][preve[v]].cap);
            }
            f -= d;
            res += d * distance[t];
            for (int v = t; v != s; v = prevv[v])
            {
                edge &e = G[prevv[v]][preve[v]];
                e.cap -= d;
                G[v][e.rev].cap += d;
            }
        }
        return res;
    }

    // Potential-based method O(FElogV)
    T mcfDijkstra(int s, int t, T f)
    {
        T res = 0;
        h = std::vector<T>(V, (T)0);
        while (f > 0)
        {
            std::priority_queue<P, std::vector<P>, std::greater<P> > que;
            distance = std::vector<T>(V, INF);
            distance[s] = (T)0;
            que.push(P((T)0, s));
            while (!que.empty())
            {
                P p = que.top();
                que.pop();
                int v = p.second;
                if (distance[v] < p.first) continue;
                for (unsigned i = 0; i < G[v].size(); i++)
                {
                    edge &e = G[v][i];
                    if (e.cap > 0 && distance[e.to] > distance[v] + e.cost + h[v] - h[e.to])
                    {
                        distance[e.to] = distance[v] + e.cost + h[v] - h[e.to];
                        prevv[e.to] = v;
                        preve[e.to] = i;
                        que.push(P(distance[e.to], e.to));
                    }
                }
            }
            if (distance[t] == INF)
            {
                return -1;
            }
            for (int v = 0; v < V; v++) h[v] += distance[v];

            T d = f;
            for (int v = t; v != s; v=prevv[v])
            {
                d = std::min(d, G[prevv[v]][preve[v]].cap);
            }
            f -= d;
            res += d * h[t];
            for (int v = t; v != s; v = prevv[v])
            {
                edge &e = G[prevv[v]][preve[v]];
                e.cap -= d;
                G[v][e.rev].cap += d;
            }
        }
        return res;
    }
};

int main()
{
    lint N;
    cin >> N;
    vector<lint> RX(N);
    vector<lint> RY(N);
    vector<lint> RC(N);
    REP(i, N){ cin >> RX[i]; cin >> RY[i]; cin >> RC[i]; }
    vector<lint> BX(N);
    vector<lint> BY(N);
    vector<lint> BC(N);
    REP(i, N){ cin >> BX[i]; cin >> BY[i]; cin >> BC[i]; }

    vector<lint> xpy, xmy;
    REP(i, N)
    {
        xpy.push_back(RX[i] + RY[i]);
        xpy.push_back(BX[i] + BY[i]);
        xmy.push_back(RX[i] - RY[i]);
        xmy.push_back(BX[i] - BY[i]);
    }
    sort(ALL(xpy));
    sort(ALL(xmy));
    xpy.erase(unique(ALL(xpy)), xpy.end());
    xmy.erase(unique(ALL(xmy)), xmy.end());
    while (xpy.size() < xmy.size())
    {
        xpy.push_back(xpy.back() * 1);
    }
    while (xpy.size() > xmy.size())
    {
        xmy.push_back(xmy.back() + 1);
    }
    int U = xpy.size(), V = xmy.size();
    map<lint, int> xpyinv, xmyinv;
    int i = 0;
    for (auto v : xpy) xpyinv[v] = i++;
    i = 0;
    for (auto v : xmy) xmyinv[v] = i++;

    lint diff_max = 0;
    REP(i, U - 1) mmax(diff_max, xpy[i + 1] - xpy[i]);
    REP(i, V - 1) mmax(diff_max, xmy[i + 1] - xmy[i]);


    MinCostFlow<lint> mcf(N * 2 + 2 + U * 2 + V * 2);
    REP(i, U - 1)
    {
        mcf.add_edge(N * 2 + 2 + i, N * 2 + 2 + i + 1, 10000, diff_max - xpy[i + 1] + xpy[i]);
        mcf.add_edge(N * 2 + 2 + i + 1 + U, N * 2 + 2 + i + U, 10000, diff_max - xpy[i + 1] + xpy[i]);
    }
    int TT = N * 2 + 2 + 2 * U;
    REP(i, V - 1)
    {
        mcf.add_edge(TT + i,  TT + i + 1, 10000, diff_max - xmy[i + 1] + xmy[i]);
        mcf.add_edge(TT + V + i + 1, TT + V + i, 10000, diff_max - xmy[i + 1] + xmy[i]);
    }

    REP(i, N)
    {
        mcf.add_edge(0, i + 1, RC[i], 0);
        mcf.add_edge(N + 1 + i, N * 2 + 1, BC[i], 0);
    }
    REP(i, N)
    {
        lint XPY = RX[i] + RY[i], XMY = RX[i] - RY[i];
        int xpyid = xpyinv[XPY];
        int xmyid = xmyinv[XMY];
        mcf.add_edge(i + 1, N * 2 + 2 + xpyid, RC[i], diff_max * xpyid);
        mcf.add_edge(i + 1, N * 2 + 2 + xpyid + U, RC[i], diff_max * (U - 1 - xpyid));
        mcf.add_edge(i + 1, N * 2 + 2 + U * 2 + xmyid, RC[i], diff_max * xmyid);
        mcf.add_edge(i + 1, N * 2 + 2 + U * 2 + xmyid + V, RC[i], diff_max * (V - 1 - xmyid));
    }

    REP(i, N)
    {
        lint XPY = BX[i] + BY[i], XMY = BX[i] - BY[i];
        int xpyid = xpyinv[XPY];
        int xmyid = xmyinv[XMY];
        mcf.add_edge(N * 2 + 2 + xpyid, N + 1 + i, BC[i], diff_max * (U - 1 - xpyid));
        mcf.add_edge(N * 2 + 2 + xpyid + U, N + 1 + i, BC[i], diff_max * xpyid);
        mcf.add_edge(N * 2 + 2 + U * 2 + xmyid, N + 1 + i, BC[i], diff_max * (V - 1 - xmyid));
        mcf.add_edge(N * 2 + 2 + U * 2 + xmyid + V, N + 1 + i, BC[i], diff_max * xmyid);
    }

    lint tot_flow = accumulate(ALL(RC), 0LL);
    lint ret = mcf.mcfDijkstra(0, 2 * N + 1, tot_flow);
    cout << (U - 1) * diff_max * tot_flow - ret << endl;
}


Measured memory_bytes: 2776