#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using lint = long long; using pint = pair; using plint = pair; struct fast_ios { fast_ios(){ cin.tie(nullptr), ios::sync_with_stdio(false), cout << fixed << setprecision(20); }; } fast_ios_; #define ALL(x) (x).begin(), (x).end() #define FOR(i, begin, end) for(int i=(begin),i##_end_=(end);i=i##_begin_;i--) #define REP(i, n) FOR(i,0,n) #define IREP(i, n) IFOR(i,0,n) template void ndarray(vector& vec, const V& val, int len) { vec.assign(len, val); } template void ndarray(vector& vec, const V& val, int len, Args... args) { vec.resize(len), for_each(begin(vec), end(vec), [&](T& v) { ndarray(v, val, args...); }); } template bool chmax(T &m, const T q) { return m < q ? (m = q, true) : false; } template bool chmin(T &m, const T q) { return m > q ? (m = q, true) : false; } const std::vector> grid_dxs{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; int floor_lg(long long x) { return x <= 0 ? -1 : 63 - __builtin_clzll(x); } template T1 floor_div(T1 num, T2 den) { return (num > 0 ? num / den : -((-num + den - 1) / den)); } template std::pair operator+(const std::pair &l, const std::pair &r) { return std::make_pair(l.first + r.first, l.second + r.second); } template std::pair operator-(const std::pair &l, const std::pair &r) { return std::make_pair(l.first - r.first, l.second - r.second); } template std::vector sort_unique(std::vector vec) { sort(vec.begin(), vec.end()), vec.erase(unique(vec.begin(), vec.end()), vec.end()); return vec; } template int arglb(const std::vector &v, const T &x) { return std::distance(v.begin(), std::lower_bound(v.begin(), v.end(), x)); } template int argub(const std::vector &v, const T &x) { return std::distance(v.begin(), std::upper_bound(v.begin(), v.end(), x)); } template IStream &operator>>(IStream &is, std::vector &vec) { for (auto &v : vec) is >> v; return is; } template OStream &operator<<(OStream &os, const std::vector &vec); template OStream &operator<<(OStream &os, const std::array &arr); template OStream &operator<<(OStream &os, const std::unordered_set &vec); template OStream &operator<<(OStream &os, const pair &pa); template OStream &operator<<(OStream &os, const std::deque &vec); template OStream &operator<<(OStream &os, const std::set &vec); template OStream &operator<<(OStream &os, const std::multiset &vec); template OStream &operator<<(OStream &os, const std::unordered_multiset &vec); template OStream &operator<<(OStream &os, const std::pair &pa); template OStream &operator<<(OStream &os, const std::map &mp); template OStream &operator<<(OStream &os, const std::unordered_map &mp); template OStream &operator<<(OStream &os, const std::tuple &tpl); template OStream &operator<<(OStream &os, const std::vector &vec) { os << '['; for (auto v : vec) os << v << ','; os << ']'; return os; } template OStream &operator<<(OStream &os, const std::array &arr) { os << '['; for (auto v : arr) os << v << ','; os << ']'; return os; } template std::istream &operator>>(std::istream &is, std::tuple &tpl) { std::apply([&is](auto &&... args) { ((is >> args), ...);}, tpl); return is; } template OStream &operator<<(OStream &os, const std::tuple &tpl) { os << '('; std::apply([&os](auto &&... args) { ((os << args << ','), ...);}, tpl); return os << ')'; } template OStream &operator<<(OStream &os, const std::unordered_set &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; } template OStream &operator<<(OStream &os, const std::deque &vec) { os << "deq["; for (auto v : vec) os << v << ','; os << ']'; return os; } template OStream &operator<<(OStream &os, const std::set &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; } template OStream &operator<<(OStream &os, const std::multiset &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; } template OStream &operator<<(OStream &os, const std::unordered_multiset &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; } template OStream &operator<<(OStream &os, const std::pair &pa) { return os << '(' << pa.first << ',' << pa.second << ')'; } template OStream &operator<<(OStream &os, const std::map &mp) { os << '{'; for (auto v : mp) os << v.first << "=>" << v.second << ','; os << '}'; return os; } template OStream &operator<<(OStream &os, const std::unordered_map &mp) { os << '{'; for (auto v : mp) os << v.first << "=>" << v.second << ','; os << '}'; return os; } #ifdef HITONANODE_LOCAL const string COLOR_RESET = "\033[0m", BRIGHT_GREEN = "\033[1;32m", BRIGHT_RED = "\033[1;31m", BRIGHT_CYAN = "\033[1;36m", NORMAL_CROSSED = "\033[0;9;37m", RED_BACKGROUND = "\033[1;41m", NORMAL_FAINT = "\033[0;2m"; #define dbg(x) std::cerr << BRIGHT_CYAN << #x << COLOR_RESET << " = " << (x) << NORMAL_FAINT << " (L" << __LINE__ << ") " << __FILE__ << COLOR_RESET << std::endl #define dbgif(cond, x) ((cond) ? std::cerr << BRIGHT_CYAN << #x << COLOR_RESET << " = " << (x) << NORMAL_FAINT << " (L" << __LINE__ << ") " << __FILE__ << COLOR_RESET << std::endl : std::cerr) #else #define dbg(x) ((void)0) #define dbgif(cond, x) ((void)0) #endif #include #include #include #include // 2次元の kd-tree // 矩形内の全頂点取得が可能 // Verified: abc234h https://atcoder.jp/contests/abc234/submissions/28456735 template struct kd_tree { std::vector> _ps; struct Node { T xmin, xmax, ymin, ymax; std::vector ids; int lch, rch; template friend OStream &operator<<(OStream &os, const Node &n) { os << "{Node[" << n.xmin << ", " << n.xmax << "]x[" << n.ymin << ", " << n.ymax << "], ids=("; for (auto i : n.ids) os << i << ','; os << "), chs=" << n.lch << ',' << n.rch << '}'; return os; } }; std::vector _nodes; using Tpl = std::tuple; std::vector _tmp; int _build(int l, int r, int nsplitx, int nsplity) { if (l >= r) return -1; T xmin = std::get<1>(_tmp[l]), xmax = xmin, ymin = std::get<2>(_tmp[l]), ymax = ymin; std::vector ids(r - l); for (int i = l; i < r; ++i) { T x = std::get<1>(_tmp[i]), y = std::get<2>(_tmp[i]); if (x < xmin) xmin = x; if (x > xmax) xmax = x; if (y < ymin) ymin = y; if (y > ymax) ymax = y; ids[i - l] = std::get<0>(_tmp[i]); } const int _node_id = _nodes.size(); _nodes.push_back({xmin, xmax, ymin, ymax, ids, -1, -1}); // Decide which direction to split bool split_x = xmax - xmin > ymax - ymin; if (nsplitx > 3) split_x = false; // 同じ方向に何度も連続で切らない if (nsplity > 3) split_x = true; if (r - l > 1) { int c = (l + r) / 2; if (split_x) { // split x std::nth_element( _tmp.begin() + l, _tmp.begin() + c, _tmp.begin() + r, [&](const Tpl &l, const Tpl &r) { return std::get<1>(l) < std::get<1>(r); }); _nodes[_node_id].lch = _build(l, c, nsplitx + 1, 0); _nodes[_node_id].rch = _build(c, r, nsplitx + 1, 0); } else { // split y std::nth_element( _tmp.begin() + l, _tmp.begin() + c, _tmp.begin() + r, [&](const Tpl &l, const Tpl &r) { return std::get<2>(l) < std::get<2>(r); }); _nodes[_node_id].lch = _build(l, c, 0, nsplity + 1); _nodes[_node_id].rch = _build(c, r, 0, nsplity + 1); } } return _node_id; } void _initialize(const std::vector> &vs) { _ps = vs; _tmp.resize(_ps.size()); for (int i = 0; i < int(vs.size()); ++i) _tmp[i] = std::make_tuple(i, vs[i].first, vs[i].second); _build(0, _tmp.size(), 0, 0); } kd_tree(const std::vector> &vs) { _initialize(vs); } std::vector get_rect(T xmin, T xmax, T ymin, T ymax) const { // [xmin, xmax] * [ymin, ymax] に含まれる全点取得 std::vector ret; std::vector _stack; if (_nodes.size()) _stack.push_back(0); while (!_stack.empty()) { const Node &now = _nodes[_stack.back()]; _stack.pop_back(); if (xmax < now.xmin or now.xmax < xmin or ymax < now.ymin or now.ymax < ymin) { ; } else if (xmin <= now.xmin and now.xmax <= xmax and ymin <= now.ymin and now.ymax <= ymax) { ret.insert(ret.end(), now.ids.begin(), now.ids.end()); } else { if (now.lch >= 0) _stack.push_back(now.lch); if (now.rch >= 0) _stack.push_back(now.rch); } } return ret; } }; // Mo's algorithm // - add_range(l, r) : Add [l, r) as query. // - run() : run Mo's algorithm. template class MosAlgorithm { Int nmin, nmax; public: struct Point { Int first, second; int qid; }; std::vector ranges; MosAlgorithm() : nmin(INF), nmax(-INF) {} void add_range(Int l, Int r, int q) { assert(l <= r); nmin = std::min(nmin, l); nmax = std::max(nmax, r); ranges.push_back(Point{l, r, q}); } std::vector run() { const int Q = ranges.size(); const int nbbucket = std::max(1, std::min(nmax - nmin, sqrt(Q))); const Int szbucket = (nmax - nmin + nbbucket - 1) / nbbucket; std::vector qs(Q); std::iota(qs.begin(), qs.end(), 0); std::sort(qs.begin(), qs.end(), [&](int q1, int q2) { auto b1 = (ranges[q1].first - nmin) / szbucket, b2 = (ranges[q2].first - nmin) / szbucket; if (b1 != b2) return b1 < b2; else { return (b1 & 1) ? (ranges[q1].second > ranges[q2].second) : (ranges[q1].second < ranges[q2].second); } }); return qs; } }; uint32_t rand_int() // XorShift random integer generator { static uint32_t x = 123456789, y = 362436069, z = 521288629, w = 88675123; uint32_t t = x ^ (x << 11); x = y; y = z; z = w; return w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)); } double rand_double() { return (double)rand_int() / UINT32_MAX; } using Cost = lint; vector xs; Cost calc_dist(int i, int j) { auto dx = xs.at(j) - xs.at(i); return abs(dx.first) + abs(dx.second); } std::mt19937 mt(100); #include template struct SymmetricTSP { int _n; inline T dist(int s, int t) const noexcept { return calc_dist(s, t); } struct Solution { T primal; std::vector path; template friend OStream &operator<<(OStream &os, const Solution &x) { os << "[primal sol=" << x.primal << ", path=("; if (!x.path.empty()) { for (int i : x.path) os << i << ">"; os << x.path.front() << ")]"; } return os; } }; std::vector>> adjacents; void build_adjacent_info(std::vector>> &info_) { adjacents = info_; } SymmetricTSP(int n) : _n(n) {} Solution nearest_neighbor(std::optional init = std::nullopt) const { if (n() == 0) return {T(), {}}; int now = init.value_or(0); std::vector ret{now}, alive(n(), 1); T len = T(); ret.reserve(n()); alive.at(now) = 0; while (int(ret.size()) < n()) { int nxt = -1; for (int i = 0; i < n(); ++i) { if (alive.at(i) and (nxt < 0 or dist(now, i) < dist(now, nxt))) nxt = i; } ret.push_back(nxt); alive.at(nxt) = 0; len += dist(now, nxt); now = nxt; } len += dist(ret.back(), ret.front()); return Solution{len, ret}; } void two_opt(Solution &sol) const { while (true) { bool updated = false; for (int i = 0; i + 1 < n() and !updated; ++i) { int u = sol.path.at(i), nxtu = sol.path.at(i + 1); for (int j = i + 2; j < n(); ++j) { int v = sol.path.at(j), nxtv = sol.path.at(j + 1 < n() ? j + 1 : 0); T diff = dist(u, v) + dist(nxtu, nxtv) - dist(u, nxtu) - dist(v, nxtv); if (diff < 0) { sol.primal += diff; std::reverse(sol.path.begin() + i + 1, sol.path.begin() + j + 1); updated = true; break; } } } if (!updated) break; } } template void two_opt_near(Solution &sol, Clock &START) { // if (adjacents.empty()) build_adjacent_info(20); static std::vector v_to_i; v_to_i.resize(n()); while (true) { int64_t spent_ms = std::chrono::duration_cast(std::chrono::system_clock::now() - START).count(); if (spent_ms > 4700) break; // dbg(sol.primal); for (int i = 0; i < n(); ++i) v_to_i.at(sol.path.at(i)) = i; bool updated = false; for (int i = 0; i < n() and !updated; ++i) { int u = sol.path.at(i), nxtu = sol.path.at(modn(i + 1)); T dunxtu = dist(u, nxtu); for (auto [duv, v] : adjacents.at(u)) { if (v == nxtu) continue; int j = v_to_i.at(v), nxtv = sol.path.at(modn(j + 1)); T diff = duv + dist(nxtu, nxtv) - dunxtu - dist(v, nxtv); if (diff < 0) { sol.primal += diff; if (i < j) { std::reverse(sol.path.begin() + i + 1, sol.path.begin() + j + 1); } else { std::reverse(sol.path.begin() + j + 1, sol.path.begin() + i + 1); } updated = true; break; } } if (updated) break; for (auto [dnxtunxtv, nxtv] : adjacents.at(nxtu)) { if (nxtv == u) continue; int j = modn(v_to_i.at(nxtv) - 1), v = sol.path.at(j); T diff = dist(u, v) + dnxtunxtv - dunxtu - dist(v, nxtv); if (diff < 0) { sol.primal += diff; if (i < j) { std::reverse(sol.path.begin() + i + 1, sol.path.begin() + j + 1); } else { std::reverse(sol.path.begin() + j + 1, sol.path.begin() + i + 1); } updated = true; break; } } } if (!updated) break; } } bool three_opt(Solution &sol, const int max_size = 0) const { for (int s = 1; s < (max_size > 0 ? max_size : n()); ++s) { for (int i = 0; i < n(); ++i) { for (int l = s + 1; l < n(); ++l) { int u = sol.path.at(modn(i - 1)), nxtu = sol.path.at(i); int v = sol.path.at(modn(i + s - 1)), nxtv = sol.path.at(modn(i + s)); int w = sol.path.at(modn(i + l - 1)), nxtw = sol.path.at(modn(i + l)); T current = dist(u, nxtu) + dist(v, nxtv) + dist(w, nxtw); if (T diff = dist(u, nxtv) + dist(w, nxtu) + dist(v, nxtw) - current; diff < T()) { sol.primal += diff; std::rotate(sol.path.begin(), sol.path.begin() + i, sol.path.end()); std::rotate(sol.path.begin(), sol.path.begin() + s, sol.path.begin() + l); return true; } if (T diff = dist(u, w) + dist(nxtv, nxtu) + dist(v, nxtw) - current; diff < T()) { sol.primal += diff; std::rotate(sol.path.begin(), sol.path.begin() + i, sol.path.end()); std::rotate(sol.path.begin(), sol.path.begin() + s, sol.path.begin() + l); std::reverse(sol.path.begin(), sol.path.begin() + (l - s)); return true; } if (T diff = dist(u, nxtv) + dist(w, v) + dist(nxtu, nxtw) - current; diff < T()) { sol.primal += diff; std::rotate(sol.path.begin(), sol.path.begin() + i, sol.path.end()); std::rotate(sol.path.begin(), sol.path.begin() + s, sol.path.begin() + l); std::reverse(sol.path.begin() + (l - s), sol.path.begin() + l); return true; } if (T diff = dist(u, v) + dist(nxtu, w) + dist(nxtv, nxtw) - current; diff < T()) { sol.primal += diff; std::rotate(sol.path.begin(), sol.path.begin() + i, sol.path.end()); std::reverse(sol.path.begin(), sol.path.begin() + s); std::reverse(sol.path.begin() + s, sol.path.begin() + l); return true; } } } } return false; } bool double_bridge(Solution &sol, std::mt19937 &mt) const { if (n() < 8) return false; std::vector &p = sol.path; int rand_rot = std::uniform_int_distribution(0, n() - 1)(mt); std::rotate(p.begin(), p.begin() + rand_rot, p.end()); static std::array arr; for (int &y : arr) y = std::uniform_int_distribution(2, n() - 6)(mt); std::sort(arr.begin(), arr.end()); const int i = arr.at(0), j = arr.at(1) + 2, k = arr.at(2) + 4; static std::array diffs; for (int d = 0; d < 2; ++d) { int u = p.at(n() - 1), nxtu = p.at(0); int v = p.at(i - 1), nxtv = p.at(i); int w = p.at(j - 1), nxtw = p.at(j); int x = p.at(k - 1), nxtx = p.at(k); diffs.at(d) = dist(u, nxtu) + dist(v, nxtv) + dist(w, nxtw) + dist(x, nxtx); if (d == 1) break; std::reverse(p.begin(), p.begin() + i); std::reverse(p.begin() + i, p.begin() + j); std::reverse(p.begin() + j, p.begin() + k); std::reverse(p.begin() + k, p.end()); } sol.primal += diffs.at(1) - diffs.at(0); return true; } int n() const noexcept { return _n; } int modn(int x) const noexcept { if (x < 0) return x + n(); if (x >= n()) return x - n(); return x; } }; Cost eval(const vector &seq) { Cost cost = 0; FOR(i, 1, seq.size()) cost += calc_dist(seq.at(i - 1), seq.at(i)); return cost; } #include int main() { auto START = std::chrono::system_clock::now(); int N, Q, WT, ST; cin >> N >> Q >> WT >> ST; vector W(N); cin >> W; vector scale(N + 1); REP(i, N) scale.at(i + 1) = scale.at(i) + W.at(i); xs.resize(Q); for (auto &[x, y] : xs) { cin >> x >> y; --x; x = scale.at(x), y = scale.at(y); } // dbg(xs); vector uvs(Q); REP(q, Q) { auto [x, y] = xs.at(q); uvs.at(q) = make_pair(x + y, x - y); } kd_tree tree(uvs); vector>> neis(Q); constexpr int AS = 4; dbg("KD BUILD"); REP(q, Q) { lint w = 1 << 7; const auto [u, v] = uvs.at(q); vector nei_q; while (nei_q.size() < AS and nei_q.size() < Q) { w *= 2; nei_q = tree.get_rect(u - w, u + w + 1, v - w, v + w + 1); } for (auto i : nei_q) { if (i != q) neis.at(q).emplace_back(calc_dist(q, i), i); } sort(neis.at(q).begin(), neis.at(q).end()); while (neis.at(q).size() > AS) neis.at(q).pop_back(); } dbg("KD BUILD DONE"); MosAlgorithm mo; REP(q, Q) mo.add_range(xs.at(q).first, xs.at(q).second, q); SymmetricTSP::Solution sol{Cost(0), mo.run()}; dbg("INIT SOL BUILD"); // dbg(neis); SymmetricTSP tsp(Q); tsp.build_adjacent_info(neis); dbg("Solve 2-opt"); dbg(eval(sol.path)); tsp.two_opt_near(sol, START); dbg(eval(sol.path)); for (auto q : sol.path) cout << q + 1 << " "; cout << endl; }