#include <iostream>
#include <vector>
#include <cmath>
#include <string>
#include <climits>
#include <iomanip>
#include <algorithm>
#include <queue>
#include <map>
#include <tuple>
#include <iostream>
#include <deque>
#include <array>
#include <set>
#include <functional>
#include <memory>
#include <stack>


struct Edge {
	int to, pair, flow;
	long long int cost;
	Edge(const int t, const int p, const int f, const long long int c) :to{ t }, pair{ p }, cost{ c }, flow{ f }{};
};
struct Coordinate {
	int x, y;
};
void add_edge(std::vector<std::vector<Edge>>& nodes, const int from, const int to, const int flow, const long long int cost) {
	nodes[from].emplace_back(to, nodes[to].size(), flow, cost);
	nodes[to].emplace_back(from, nodes[from].size() - 1, 0, -cost);
}
std::vector<std::vector<Edge>> make_network(const std::vector<std::pair<Coordinate, int>>& reds, const std::vector<std::pair<Coordinate, int>>& blues) {
	const int mid = reds.size() + blues.size();
	const int source = mid + 4;
	const int drain = source + 1;
	std::vector<std::vector<Edge>> result(drain + 1);
	for (auto i = 0; i < reds.size(); ++i) {add_edge(result, source, i, reds[i].second, 0);}
	for (auto i = 0; i < blues.size(); ++i) { add_edge(result, i + reds.size(), drain, blues[i].second, 0); }
	for (auto t = 0; t < 4; ++t) {
		long long int x = ((t & 2) == 0) ? 1L : -1L;
		long long int y = ((t & 1) == 0) ? 1L : -1L;
		for (auto i = 0; i < reds.size(); ++i) { 
			add_edge(result, i, mid + t, reds[i].second, 2000000000LL + x * reds[i].first.x + y * reds[i].first.y); 
			add_edge(result, mid + t, i + reds.size(), blues[i].second, 2000000000LL - x * blues[i].first.x - y * blues[i].first.y);
		}
	}
	return result;
}
long long int cal_min_cost_maxflow(std::vector<std::vector<Edge>> nodes) {
	const int source = nodes.size() - 2;
	const int drain = source + 1;
	std::vector<long long int> potential(nodes.size(), 0), min_cost(nodes.size(), LLONG_MAX);
	std::vector<Edge*> prev(nodes.size(), nullptr);
	std::priority_queue<std::pair<long long int, int>, std::vector<std::pair<long long int, int>>, std::function<bool(const std::pair<long long int, int>, const std::pair<long long int, int>)>>  queue([](const std::pair<long long int, int> a, const std::pair<long long int, int> b) {return a.first > b.first; });
	long long int result = 0L;
	while (true) {
		min_cost[source] = 0;
		queue.emplace(0, source);
		while (!queue.empty()) {
			auto cost = queue.top().first; auto current = queue.top().second; queue.pop();
			if (min_cost[current] == cost && current != drain) {
				for (const auto& next : nodes[current]) if (next.flow > 0) {
					if (min_cost[next.to] > potential[next.to] + cost + next.cost - potential[current]) {
						min_cost[next.to] = potential[next.to] + cost + next.cost - potential[current];
						prev[next.to] = &nodes[next.to][next.pair];
						queue.emplace(min_cost[next.to], next.to);
					}
				}
			}
		}
		if (min_cost[drain] == LLONG_MAX) return result;
		auto last = drain;
		auto min_flow = INT_MAX;
		while (last != source) {
			min_flow = std::min(nodes[prev[last]->to][prev[last]->pair].flow, min_flow);
			last = prev[last]->to;
		}
		result += min_flow * min_cost[drain];
		last = drain;
		while (last != source) {
			auto e = prev[last];
			e->flow += min_flow;
			nodes[e->to][e->pair].flow -= min_flow;
			last = e->to;
		}
		for (auto i = 0; i < nodes.size(); ++i) {
			if (i != drain && min_cost[i] != LLONG_MAX) potential[i] -= min_cost[i];
		}
		std::fill(min_cost.begin(), min_cost.end(), LLONG_MAX);
	}
}
int main() {
	int n; std::cin >> n;
	std::vector<std::pair<Coordinate, int>> reds(n), blues(n);
	for (auto& r : reds) std::cin >> r.first.x >> r.first.y >> r.second;
	for (auto& b : blues) std::cin >> b.first.x >> b.first.y >> b.second;
	long long int count = 0LL;
	for (const auto r : reds) count += r.second;
	std::cout << count * 4000000000LL - cal_min_cost_maxflow(make_network(reds, blues)) << std::endl;
}

Measured memory_bytes: 1280