#include using namespace std; typedef long long ll; template void check_min(T &a, const T &b){ a = (a < b) ? a : b; } template void check_max(T &a, const T &b){ a = (a > b) ? a : b; } #define all(x) (x).begin(), (x).end() typedef long double ld; const int N = 5e4 + 3; const ld INF = 1e24; mt19937_64 mt(3); int n, m; vector> soldiers, towers; clock_t timer = clock(); bool time_left(){ return (((float)clock() - (float)timer) / (float)CLOCKS_PER_SEC) <= 4; } ld square(ld x){ return x * x; } ll dist2(array a, array b){ return square(a[0] - a[1]) + square(b[0] - b[1]); } struct Solution{ vector> orders; ld score; Solution(){ score = INF; } void add(array operation){ if(orders.empty()){ score = 0; } auto [x1, y1, x2, y2, q] = operation; score += sqrt(square((ld)x1 - x2) + square((ld)y1 - y2)) * q; orders.push_back(operation); // cout << "add " << operation[0] << " " << operation[1] << " " << operation[2] << " " << operation[3] << " " << operation[4] << endl; } friend bool operator<(const Solution &l, const Solution &r){ return l.score < r.score; } friend bool operator>(const Solution &l, const Solution &r){ return l.score > r.score; } } best; template struct PointSet{ vector> points; void init(const vector> points){ this->points = points; } bool empty() const { return points.empty(); } int closest(array s_point){ int best_idx; ll best_dist = LLONG_MAX; for(int i = 0; i < iterations; ++i){ int idx = mt() % points.size(); ll cand_dist = dist2({points[idx][0], points[idx][1]}, s_point); if(cand_dist < best_dist){ best_dist = cand_dist; best_idx = idx; } } return best_idx; } void clear(){ points.clear(); } array operator[](int idx){ return points[idx]; } void erase(int idx){ swap(points[idx], points.back()); points.pop_back(); } void insert(array point){ points.push_back(point); } }; bool attempt(int bundle_size, vector> soldiers, vector> towers){ Solution sol; static PointSet<50> s_set; s_set.init(soldiers); vector> new_soldiers; for(int left = 0; left < n; left += bundle_size){ auto soldier = s_set[0]; s_set.erase(0); for(int i = left + 1; i < min(left + bundle_size, n); ++i){ auto closest_idx = s_set.closest({soldier[0], soldier[1]}); auto new_soldier = s_set[closest_idx]; s_set.erase(closest_idx); sol.add(array{new_soldier[0], new_soldier[1], soldier[0], soldier[1], new_soldier[2]}); soldier[2] += new_soldier[2]; } new_soldiers.push_back(soldier); } s_set.init(new_soldiers); for(auto [x, y, cnt]: towers){ bool matched = false; while(!matched && !s_set.empty()){ int closest_idx = s_set.closest({x, y}); auto soldier = s_set[closest_idx]; s_set.erase(closest_idx); if(soldier[2] < cnt) continue; sol.add(array{soldier[0], soldier[1], x, y, soldier[2]}); soldier[0] = x; soldier[1] = y; soldier[2] = sqrt(soldier[2] * soldier[2] - cnt * cnt) + 0.99; s_set.insert(soldier); matched = true; } if(!matched) return false; } if(sol < best){ best = sol; // cerr << "new best: " << best.score << endl; // cerr << bundle_size << endl; } // cout << bundle_size << " :)" << endl; return true; } void solve(){ sort(all(soldiers)); sort(all(towers)); int mx = 0; for(int bundle_size = 1; bundle_size <= n && time_left(); bundle_size *= 2){ // cerr << bundle_size << " BUNDLE_SIZE" << endl; auto successful = attempt(bundle_size, soldiers, towers); // cerr << successful << " successful" << endl; check_max(mx, bundle_size); } if(time_left()){ int bundle_size = n; attempt(bundle_size, soldiers, towers); } // cerr << mx << " mx" << endl; } void read(){ freopen("war.in", "r", stdin); freopen("war.out", "w", stdout); ios::sync_with_stdio(false); cin.tie(NULL); cin >> n >> m; soldiers.resize(n); towers.resize(m); for(int i = 0; i < n; ++i) for(int j = 0; j < 3; ++j) cin >> soldiers[i][j]; for(int i = 0; i < n; ++i) for(int j = 0; j < 3; ++j) cin >> towers[i][j]; } void write(){ // cerr << "SCORE: " << best.score << endl; cout << best.orders.size() << "\n"; for(auto arr: best.orders){ for(auto x: arr) cout << x << " "; cout << "\n"; } } int main(){ read(); solve(); write(); }