#include <stdio.h>
#include <algorithm>
#include <utility>
#include <functional>
#include <cstring>
#include <queue>
#include <stack>
#include <cmath>
#include <iterator>
#include <vector>
#include <string>
#include <set>
#include <iostream>
#include <random>
#include <map>
#include <iomanip>
#include <stdlib.h>
#include <list>
#include <typeinfo>
#include <list>
#include <set>
#include <cassert>
#include <fstream>
#include <unordered_map>
#include <cstdlib>
#include <complex>
#include <cctype>
#include <bitset>
using namespace std;

using ll = long long;
using vll = vector<ll>;
using pll = pair<ll, ll>;
using qll = queue<ll>;
using vb = vector<bool>;
using mll = map<ll, ll>;
using sll = stack<ll>;
#define REP(i,n) for(ll i(0);(i)<(n);(i)++)
#define rep(i,n) for(ll i(0);(i)<(n);(i)++)
#define ALL(a) a.begin(), a.end()
#define elnd endl //* missspell check
const ll INF = 1LL << 60;


struct edge{ ll to, cap, cost, rev;};

void add_edge(vector<vector<edge> > &G, ll from, ll to, ll cap, ll cost){
    G[from].push_back((edge){to, cap,  cost, (ll)G[to].size()});
    G[to].push_back  ((edge){from, 0, -cost, (ll)G[from].size() - 1});
}
//* minimum cost flow using Bellman-Ford
//* Graph G, source s, sink t, with target flow f
//* returns minimum cost
//* returns -1 if impossible to compute required flow
ll minCostFlowBellmanFord(vector<vector<edge> > &G, ll s, ll t, ll f){
    ll N = G.size();
    vll dist(N); //* dist: shortest distance
    vll prev_v(N), prev_e(N);//* prev_v/prev_e: previous vertex/edge to record shortest path
    
    ll res = 0;
    while( f > 0){
        //* Bellman-Ford to calculate s-t shortest path
        fill(ALL(dist), INF);
        dist[s]=0;
        bool update = true;
        while(update){
            update = false;
            REP(v, N){
                if( dist[v] == INF) continue;
                REP(i, G[v].size()){
                    edge &e = G[v][i];
                    if(e.cap > 0 && dist[e.to] > dist[v] + e.cost) {
                        dist[e.to] = dist[v] + e.cost;
                        prev_v[e.to] = v;
                        prev_e[e.to] = i;
                        update = true;
                    }
                }
            }
        }
        
        if(dist[t] == INF){ //* s is disconnected from t, meaning f is not reachable
            return -1;
        }
        //* run flow as many as possible along shortest path
        ll d = f;
        for(ll v = t; v != s; v = prev_v[v]){
            //* v --> prev_v[v] via prev_e[v]
            d = min(d, G[prev_v[v]][prev_e[v]].cap);
        }
        f -= d;
        res += d * dist[t];
        //* update residual graph along shortest path
        for(ll v = t; v != s; v = prev_v[v]){
            edge &e = G[prev_v[v]][prev_e[v]];
            e.cap -= d;
            G[v][e.rev].cap += d;
        }
    }
    return res;        
}

//! minimum cost flow using Dijkstra, the initial graph should contains NO negative edge
//* Graph G, source s, sink t, with target flow f
//* returns minimum cost
//* returns -1 if impossible to compute required flow
ll minCostFlowDijkstra(vector<vector<edge> > &G, ll s, ll t, ll f){
    ll N = G.size();
    vll dist(N); //* dist: shortest distance
    vll prev_v(N), prev_e(N);//* prev_v/prev_e: previous vertex/edge to record shortest path
    vll h(N); //* potential for each vertex
    
    ll res = 0;
    fill(ALL(h), 0);
    while( f > 0){
        //* Use Dijkstra to update potential h
        priority_queue<pll, vector<pll>, greater<pll> > que;
        fill(ALL(dist), INF);
        dist[s]=0;
        que.push(pll(0, s));
        while(!que.empty()){
            pll p = que.top(); que.pop();
            ll v = p.second;
            if(dist[v] < p.first) continue;
            REP(i, G[v].size()){
                edge &e = G[v][i];
                if(e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to]) {
                    dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
                    prev_v[e.to] = v;
                    prev_e[e.to] = i;
                    que.push(pll(dist[e.to], e.to));
                }
            }
        }
        
        if(dist[t] == INF){ //* s is disconnected from t, meaning f is not reachable
            return -1;
        }
        REP(v, N) h[v] += dist[v];
        //* run flow as many as possible along shortest path
        ll d = f;
        for(ll v = t; v != s; v = prev_v[v]){
            //* v --> prev_v[v] via prev_e[v]
            d = min(d, G[prev_v[v]][prev_e[v]].cap);
        }
        f -= d;
        res += d * h[t];
        //* update residual graph along shortest path
        for(ll v = t; v != s; v = prev_v[v]){
            edge &e = G[prev_v[v]][prev_e[v]];
            e.cap -= d;
            G[v][e.rev].cap += d;
        }
    }
    return res;
}

void solve(long long N, std::vector<long long> RX, std::vector<long long> RY, 
    std::vector<long long> RC, std::vector<long long> BX, std::vector<long long> BY, std::vector<long long> BC){
    
    ll S = 0;
    REP(i, N) S += RC[i];
    ll maxDist = 0;
    REP(i, N){
        REP(j, N){
            maxDist = max(maxDist, abs(RX[i]-BX[j]) + abs(RY[i]-BY[j]));
        }
    }
    ll s = 2*N, t = 2*N+1;
    vector<vector<edge>> G(2*N+2); //* source 2*N, sink 2*N+1
    //* red: 0-> N-1, blue: N->2N-1
    REP(i, N){
        add_edge(G, s, i, RC[i], 0);
        add_edge(G, i+N, t, BC[i], 0);
    }
    REP(i, N){
        REP(j, N){
            add_edge(G, i, j+N, INF, maxDist - abs(RX[i]-BX[j]) - abs(RY[i]-BY[j]));
        }
    }
    ll ans = minCostFlowDijkstra(G, s, t, S);
    cout<<maxDist*S - ans <<endl;

}

void solve2(long long N, std::vector<long long> RX, std::vector<long long> RY, 
    std::vector<long long> RC, std::vector<long long> BX, std::vector<long long> BY, std::vector<long long> BC){
    
    ll S = 0;
    ll offset = 10000000000;
    REP(i, N) S += RC[i];
    
    ll s = 2*N, t = 2*N+1, type1 = 2*N+2, type2 = 2*N+3, type3 = 2*N+4, type4 = 2*N+5;
    vector<vector<edge>> G(2*N+6); //* source 2*N, sink 2*N+1
    //* red: 0-> N-1, blue: N->2N-1
    REP(i, N){
        add_edge(G, s, i, RC[i], 0);
        add_edge(G, i+N, t, BC[i], 0);
    }
    REP(i, N){
        add_edge(G, i, type1, INF, offset - RX[i] -  RY[i]);
        add_edge(G, i, type2, INF, offset + RX[i] -  RY[i]);
        add_edge(G, i, type3, INF, offset - RX[i] +  RY[i]);
        add_edge(G, i, type4, INF, offset + RX[i] +  RY[i]);

        add_edge(G, type1, i+N, INF, offset + BX[i] + BY[i]);
        add_edge(G, type2, i+N, INF, offset - BX[i] + BY[i]);
        add_edge(G, type3, i+N, INF, offset + BX[i] - BY[i]);
        add_edge(G, type4, i+N, INF, offset - BX[i] - BY[i]);
    }
    ll ans = minCostFlowDijkstra(G, s, t, S);
    cout<<2*S*offset - ans <<endl;

}

int main(){
    long long N;
    scanf("%lld",&N);
    std::vector<long long> RX(N);
    std::vector<long long> RY(N);
    std::vector<long long> RC(N);
    for(int i = 0 ; i < N ; i++){
        scanf("%lld",&RX[i]);
        scanf("%lld",&RY[i]);
        scanf("%lld",&RC[i]);
    }
    std::vector<long long> BX(N);
    std::vector<long long> BY(N);
    std::vector<long long> BC(N);
    for(int i = 0 ; i < N ; i++){
        scanf("%lld",&BX[i]);
        scanf("%lld",&BY[i]);
        scanf("%lld",&BC[i]);
    }
    solve2(N, std::move(RX), std::move(RY), std::move(RC), std::move(BX), std::move(BY), std::move(BC));
    return 0;
}


Measured memory_bytes: 1524