|
| 1 | +/* |
| 2 | +NOI.cn 2010 Super Piano |
| 3 | +- First, build a prefix sum array of the note values |
| 4 | +- The best chord we can make starting on note i has value |
| 5 | + max(pref[j] : j from i + l to i + r) - pref[i - 1] |
| 6 | +- This is a range query, so we can use a segment tree to |
| 7 | + handle it and remove that optimal position after using it |
| 8 | +- However, there can be multiple different starting notes, |
| 9 | + so we can't just straight-up remove values from the segtree, |
| 10 | + since other starting positions could potentially depend on |
| 11 | + those |
| 12 | +- To address this, simply use a persistent segtree so that |
| 13 | + each starting position has its own segtree |
| 14 | +- There are O(K + N) nodes because we update K times |
| 15 | +- Complexity: O((K + N) log N) |
| 16 | +*/ |
| 17 | + |
| 18 | +#include <bits/stdc++.h> |
| 19 | +typedef long long ll; |
| 20 | +using namespace std; |
| 21 | + |
| 22 | +struct Node { |
| 23 | + pair<int, int> val; |
| 24 | + Node *lc, *rc; |
| 25 | + |
| 26 | + Node(pair<int, int> _val) : val(_val), lc(nullptr), rc(nullptr) {} |
| 27 | + |
| 28 | + Node(Node *_lc, Node *_rc) : lc(_lc), rc(_rc), val({INT_MIN, -1}) { |
| 29 | + if (lc) val = max(val, lc->val); |
| 30 | + if (rc) val = max(val, rc->val); |
| 31 | + } |
| 32 | +} * persist_roots[500001]; |
| 33 | + |
| 34 | +int n, x, y, k, pref[500001]; |
| 35 | + |
| 36 | +Node *build(int l = 1, int r = n) { |
| 37 | + if (l == r) return new Node({pref[l], l}); |
| 38 | + int mid = (l + r) / 2; |
| 39 | + return new Node(build(l, mid), build(mid + 1, r)); |
| 40 | +} |
| 41 | + |
| 42 | +pair<int, int> query(Node *node, int a, int b, int l = 1, int r = n) { |
| 43 | + if (!node || r < a || l > b) return {INT_MIN, -1}; |
| 44 | + if (l >= a && r <= b) return node->val; |
| 45 | + int mid = (l + r) / 2; |
| 46 | + return max(query(node->lc, a, b, l, mid), |
| 47 | + query(node->rc, a, b, mid + 1, r)); |
| 48 | +} |
| 49 | + |
| 50 | +Node *update(Node *node, int pos, int l = 1, int r = n) { |
| 51 | + if (l == r) return nullptr; |
| 52 | + int mid = (l + r) / 2; |
| 53 | + if (pos > mid) return new Node(node->lc, update(node->rc, pos, mid + 1, r)); |
| 54 | + return new Node(update(node->lc, pos, l, mid), node->rc); |
| 55 | +} |
| 56 | + |
| 57 | +int main() { |
| 58 | + cin.tie(0)->sync_with_stdio(0); |
| 59 | + cin >> n >> k >> x >> y; |
| 60 | + for (int i = 1; i <= n; i++) { |
| 61 | + int a; |
| 62 | + cin >> a; |
| 63 | + pref[i] = pref[i - 1] + a; |
| 64 | + } |
| 65 | + Node *init_root = build(); |
| 66 | + for (int i = 1; i <= n - x + 1; i++) persist_roots[i] = init_root; |
| 67 | + |
| 68 | + priority_queue<pair<int, int>> pq; |
| 69 | + for (int i = 1; i <= n - x + 1; i++) { |
| 70 | + pair<int, int> res = query(persist_roots[i], i + x - 1, i + y - 1); |
| 71 | + pq.push({res.first - pref[i - 1], i}); |
| 72 | + persist_roots[i] = update(persist_roots[i], res.second); |
| 73 | + } |
| 74 | + ll ans = 0; |
| 75 | + while (k--) { |
| 76 | + int v, i; |
| 77 | + tie(v, i) = pq.top(); |
| 78 | + pq.pop(); |
| 79 | + ans += v; |
| 80 | + pair<int, int> res = query(persist_roots[i], i + x - 1, i + y - 1); |
| 81 | + pq.push({res.first - pref[i - 1], i}); |
| 82 | + persist_roots[i] = update(persist_roots[i], res.second); |
| 83 | + } |
| 84 | + cout << ans; |
| 85 | + return 0; |
| 86 | +} |
0 commit comments