#include using namespace std; static constexpr int DL = 21; // deadlines count static constexpr int T = 181; // 06:00..21:00 in 5-min steps (inclusive) static constexpr int CH0 = 16, CH1 = 16, CH2 = 15; struct Edge { uint8_t to; uint8_t arr; }; struct PlanFlight { int from, dep, to, arr; }; static inline int parse_time_idx(const string& s) { int hh = (s[0]-'0')*10 + (s[1]-'0'); int mm = (s[3]-'0')*10 + (s[4]-'0'); int minutes = hh*60 + mm; return (minutes - 360) / 5; // 06:00=360 } static inline string fmt_time_idx(int idx) { int minutes = 360 + idx*5; int hh = minutes / 60; int mm = minutes % 60; ostringstream oss; oss << setw(2) << setfill('0') << hh << ":" << setw(2) << setfill('0') << mm; return oss.str(); } // duration in 5-min steps: ceil((40 + 60*d/800)/5) static inline int calc_dur_steps(long double dx, long double dy) { long double d = sqrtl(dx*dx + dy*dy); long double raw = 40.0L + (60.0L * d) / 800.0L; long double v = raw / 5.0L; int steps = (int)ceill(v - 1e-12L); return max(0, steps); } // --------- 47-bit weight sum by chunk lookup ---------- struct WeightSum47 { vector sum0, sum1, sum2; // 2^16,2^16,2^15 vector w; explicit WeightSum47(const vector& w_) : w(w_) { sum0.assign(1u<> 16) & 0xFFFFULL); uint32_t m2 = (uint32_t)((mask47 >> 32) & 0x7FFFULL); return sum0[m0] + sum1[m1] + sum2[m2]; } }; // --------- compute square latest depart (forward DP, from scratch) ---------- static void compute_latest_all_origins( int N, const vector>& outFlights, // size nodes = N*T vector& latest // size N*nodes ) { int nodes = N * T; latest.assign(N * nodes, (int16_t)-1); for (int o = 0; o < N; o++) { int16_t* dp = latest.data() + o * nodes; // can "start" at origin at any time t with departure time t for (int t = 0; t < T; t++) dp[o*T + t] = (int16_t)t; for (int t = 0; t < T; t++) { for (int c = 0; c < N; c++) { int node = c*T + t; int16_t val = dp[node]; if (val < 0) continue; // wait if (t+1 < T) { int node2 = node + 1; // same city, next time if (val > dp[node2]) dp[node2] = val; } // flights for (const auto& e : outFlights[node]) { int node3 = (int)e.to * T + (int)e.arr; if (val > dp[node3]) dp[node3] = val; } } } } } // --------- incremental update for circle latest depart (difference update) ---------- static void relax_add_flights_incremental( int N, vector>& outCi, // updated adjacency vector& ciLatest, // size N*nodes, updated in-place const vector& added // flights just added (for init relax) ) { int nodes = N * T; // queue buffers reused per origin (no reallocation inside loops) vector q(nodes); vector inq(nodes); for (int o = 0; o < N; o++) { int16_t* dp = ciLatest.data() + o * nodes; fill(inq.begin(), inq.end(), 0); int qh = 0, qt = 0; // initial relax only at the newly added edges for (const auto& f : added) { int fromNode = f.from*T + f.dep; int toNode = f.to*T + f.arr; int16_t val = dp[fromNode]; if (val > dp[toNode]) { dp[toNode] = val; if (!inq[toNode]) { inq[toNode] = 1; q[qt++] = toNode; } } } // propagate improvements forward in time via wait + existing flights while (qh < qt) { int node = q[qh++]; inq[node] = 0; int c = node / T; int t = node % T; int16_t val = dp[node]; // wait if (t+1 < T) { int node2 = node + 1; if (val > dp[node2]) { dp[node2] = val; if (!inq[node2]) { inq[node2] = 1; q[qt++] = node2; } } } // flights for (const auto& e : outCi[node]) { int node3 = (int)e.to * T + (int)e.arr; if (val > dp[node3]) { dp[node3] = val; if (!inq[node3]) { inq[node3] = 1; q[qt++] = node3; } } } } } } // --------- reachDest[node][k] : destinations reachable from node by deadline[k] (including transfers) ---------- static void compute_reach_dest( int N, const array& deadlines, const vector>& outCi, // circle schedule flights vector& reachDest // size nodes*DL ) { int nodes = N * T; reachDest.assign((size_t)nodes * DL, 0); vector tmp(nodes, 0); // reused per deadline for (int k = 0; k < DL; k++) { int lim = deadlines[k]; fill(tmp.begin(), tmp.end(), 0); for (int t = lim; t >= 0; --t) { for (int c = 0; c < N; c++) { int node = c*T + t; uint64_t val = 0; // wait if (t < lim) val |= tmp[node + 1]; // stay => can reach destination "c" by deadline val |= (1ULL << c); // flights for (const auto& e : outCi[node]) { if ((int)e.arr <= lim) { int node2 = (int)e.to * T + (int)e.arr; val |= tmp[node2]; } } tmp[node] = val; } } // store for all nodes (t<=lim); others remain 0 for (int c = 0; c < N; c++) { for (int t = 0; t <= lim; t++) { int node = c*T + t; reachDest[(size_t)node * DL + k] = tmp[node]; } } } } // --------- GoodDest[(o,cand),k] : destinations d where (ci<=sq) AND (sq < cand) AND eligible(o,d) ---------- static void compute_good_dest( int N, const array& deadlines, const vector& eligibleOD, // size N*N const vector& ciLatest, // size N*nodes const vector& sqDeadline, // size (N*N*DL) vector& goodDest // size (N*T*DL), index ((o*T+cand)*DL + k) ) { int nodes = N * T; goodDest.assign((size_t)N * T * DL, 0); // local bucket (on stack) to avoid heap alloc array adds; for (int o = 0; o < N; o++) { const int16_t* dp = ciLatest.data() + o * nodes; for (int k = 0; k < DL; k++) { adds.fill(0); uint64_t base = 0; int limT = deadlines[k]; for (int d = 0; d < N; d++) { if (d == o) continue; int od = o*N + d; if (!eligibleOD[od]) continue; int16_t ci = dp[d*T + limT]; int16_t sq = sqDeadline[(od*DL) + k]; // losing or tie: ci <= sq if (ci <= sq) { if (sq < 0) { base |= (1ULL << d); } else { int idx = (int)sq + 1; // include when cand >= sq+1 <=> sq < cand if (idx < T) adds[idx] |= (1ULL << d); } } } uint64_t cur = base; for (int cand = 0; cand < T; cand++) { cur |= adds[cand]; goodDest[((size_t)o * T + cand) * DL + k] = cur; } } } } // --------- edge weight: (u,t)->(v,t2) considering transfers after arrival ---------- static inline __int128 edge_weight( int N, const WeightSum47& wsum, const vector& w, const vector& ciLatest, // size N*nodes const vector& reachDest, // size nodes*DL const vector& goodDest, // size (N*T*DL) int u, int t, int v, int t2 ) { int nodes = N * T; const uint64_t* reachPtr = &reachDest[(size_t)(v*T + t2) * DL]; __int128 total = 0; for (int o = 0; o < N; o++) { const int16_t* dp = ciLatest.data() + (size_t)o * nodes; int16_t cand = dp[u*T + t]; if (cand < 0) continue; const uint64_t* goodPtr = &goodDest[((size_t)o * T + (int)cand) * DL]; long long sumWdest = 0; // DL=21 fixed small loop for (int k = 0; k < DL; k++) { uint64_t m = reachPtr[k] & goodPtr[k]; sumWdest += wsum.sum(m); } total += (__int128)w[o] * (__int128)sumWdest; } return total; } static inline string to_string_i128(__int128 x) { if (x == 0) return "0"; bool neg = false; if (x < 0) { neg = true; x = -x; } string s; while (x > 0) { int digit = (int)(x % 10); s.push_back('0' + digit); x /= 10; } if (neg) s.push_back('-'); reverse(s.begin(), s.end()); return s; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N; long long R; cin >> N >> R; vector x(N), y(N), w(N); for (int i = 0; i < N; i++) cin >> x[i] >> y[i] >> w[i]; // deadlines: 11:00, 11:30, ..., 21:00 array deadlines{}; for (int k = 0; k < DL; k++) deadlines[k] = 60 + 6*k; // duration matrix vector dur(N*N, 0); for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) if (i != j) { long double dx = (long double)x[i] - (long double)x[j]; long double dy = (long double)y[i] - (long double)y[j]; dur[i*N + j] = calc_dur_steps(dx, dy); } // eligible OD: dist >= 0.25R long double thr = 0.25L * (long double)R; long double thr2 = thr * thr; vector eligibleOD(N*N, 0); for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) if (i != j) { long double dx = (long double)x[i] - (long double)x[j]; long double dy = (long double)y[i] - (long double)y[j]; long double d2 = dx*dx + dy*dy; if (d2 + 1e-12L >= thr2) eligibleOD[i*N + j] = 1; } int M; cin >> M; int nodes = N * T; vector> outSq(nodes), outCi(nodes); // read square flights; also trust input duration if slight mismatch for (int i = 0; i < M; i++) { int a, b; string ss, ts; cin >> a >> ss >> b >> ts; --a; --b; int dep = parse_time_idx(ss); int arr = parse_time_idx(ts); if (dep < 0 || dep >= T || arr < 0 || arr >= T) continue; // fix dur if needed if (dep + dur[a*N + b] != arr) dur[a*N + b] = arr - dep; outSq[a*T + dep].push_back(Edge{(uint8_t)b, (uint8_t)arr}); } int K; cin >> K; // candidate destinations per city (pruning for speed) // 近いNEAR個 + 人口上位TOP個 を候補に const int NEAR = 8; const int TOP = 4; vector> candTo(N); // precompute order by population vector popOrder(N); iota(popOrder.begin(), popOrder.end(), 0); sort(popOrder.begin(), popOrder.end(), [&](int a, int b){ return w[a] > w[b]; }); for (int i = 0; i < N; i++) { vector> ds; ds.reserve(N-1); for (int j = 0; j < N; j++) if (j != i) { long double dx = (long double)x[i] - (long double)x[j]; long double dy = (long double)y[i] - (long double)y[j]; ds.push_back({dx*dx + dy*dy, j}); } sort(ds.begin(), ds.end()); vector v; v.reserve(NEAR + TOP); // nearest for (int k = 0; k < (int)ds.size() && (int)v.size() < NEAR; k++) { v.push_back(ds[k].second); } // top-pop for (int idx : popOrder) { if (idx == i) continue; bool exists = false; for (int t : v) if (t == idx) { exists = true; break; } if (!exists) v.push_back(idx); if ((int)v.size() >= NEAR + TOP) break; } candTo[i] = move(v); } // square latest depart vector sqLatest; compute_latest_all_origins(N, outSq, sqLatest); // sqDeadline[od*DL + k] vector sqDeadline((size_t)N*N*DL, -1); for (int o = 0; o < N; o++) { const int16_t* dp = sqLatest.data() + (size_t)o * nodes; for (int d = 0; d < N; d++) if (d != o) { int od = o*N + d; for (int k = 0; k < DL; k++) { int lim = deadlines[k]; sqDeadline[(size_t)od*DL + k] = dp[d*T + lim]; } } } // circle latest depart (incremental) vector ciLatest((size_t)N * nodes, (int16_t)-1); for (int o = 0; o < N; o++) { int16_t* dp = ciLatest.data() + (size_t)o * nodes; // start at origin at any time for (int t = 0; t < T; t++) dp[o*T + t] = (int16_t)t; } WeightSum47 wsum(w); vector reachDest; // nodes*DL vector goodDest; // (N*T*DL) vector> answer(K); // DP buffers for route search vector<__int128> best(nodes); vector parent(nodes); vector ptype(nodes); // 1=wait,2=travel for (int plane = 0; plane < K; plane++) { // rebuild reachDest for current baseline schedule (transfers included) compute_reach_dest(N, deadlines, outCi, reachDest); // rebuild GoodDest for current baseline vs square compute_good_dest(N, deadlines, eligibleOD, ciLatest, sqDeadline, goodDest); // longest path DP on time-expanded graph const __int128 NEG = -((__int128)1 << 120); fill(best.begin(), best.end(), NEG); fill(parent.begin(), parent.end(), -1); fill(ptype.begin(), ptype.end(), 0); // allow start anywhere at 06:00 (time=0) for (int c = 0; c < N; c++) best[c*T + 0] = 0; for (int t = 0; t < T-1; t++) { for (int u = 0; u < N; u++) { int node = u*T + t; __int128 cur = best[node]; if (cur <= NEG/2) continue; // wait int nodeW = node + 1; if (cur > best[nodeW]) { best[nodeW] = cur; parent[nodeW] = node; ptype[nodeW] = 1; } // travel edges (pruned candidates) for (int v : candTo[u]) { int dt = dur[u*N + v]; int t2 = t + dt; if (t2 >= T) continue; __int128 wEdge = edge_weight(N, wsum, w, ciLatest, reachDest, goodDest, u, t, v, t2); int node2 = v*T + t2; __int128 nv = cur + wEdge; if (nv > best[node2]) { best[node2] = nv; parent[node2] = node; ptype[node2] = 2; } } } } // choose best at 21:00 (time = T-1) int bestNode = 0*T + (T-1); for (int c = 1; c < N; c++) { int node = c*T + (T-1); if (best[node] > best[bestNode]) bestNode = node; } // reconstruct flights vector flights; int curNode = bestNode; while (parent[curNode] != -1) { int p = parent[curNode]; if (ptype[curNode] == 2) { int vc = curNode / T, vt = curNode % T; int uc = p / T, ut = p % T; flights.push_back(PlanFlight{uc, ut, vc, vt}); } curNode = p; } reverse(flights.begin(), flights.end()); answer[plane] = flights; // add to circle schedule + incremental update of ciLatest for (const auto& f : flights) { outCi[f.from*T + f.dep].push_back(Edge{(uint8_t)f.to, (uint8_t)f.arr}); } relax_add_flights_incremental(N, outCi, ciLatest, flights); } // output for (int i = 0; i < K; i++) { cout << answer[i].size() << "\n"; for (auto &f : answer[i]) { cout << (f.from + 1) << " " << fmt_time_idx(f.dep) << " " << (f.to + 1) << " " << fmt_time_idx(f.arr) << "\n"; } } return 0; }