Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
Process starting days from right to left. When a new day with value is prepended, starting from leaves Monocarp with before the old suffix begins. Therefore, knowing only the old suffix's answer from balance is not enough.
For each suffix, maintain the whole function : the final balance when that suffix starts with dollars. Only matters, because every daily transition keeps this range closed.
Store as an array V. For a prepended day with value , the new array is exactly V[a..2a) + V[0..M-a), where and + means concatenation.
The update only takes two slices and concatenates them, suggesting an implicit treap. The slices can overlap in the old array, so ordinary destructive split/merge is insufficient: the treap operations must use path copying.
Split the untouched old root at , split its tail after another elements to obtain V[a..2a), and independently split the old root at to obtain V[0..M-a). Merge those pieces; its first value is the current answer. Periodically flatten and rebuild the treap to control the copied-node arena.
The obvious suffix simulation is toast. The useful object for a suffix is not one answer, but the function describing what that suffix does to every possible starting balance.
Suppose the current balance is and today's value is . After the day, the balance is
Call this transition .
Balances are much more tightly bounded than the sum of all suggests. Let , which is at least . For every :
Thus every maps the integer range back into itself. We can represent an entire suffix function using exactly values.
Let be the final balance after processing days , starting day with dollars. After the holidays there are no operations, so
Prepending day gives
Suppose the array V currently stores for every . Put .
For , the first day changes into . As runs through this range, the required old indices are
For , the first day changes into , producing old indices
Therefore the complete new function array is
where means sequence concatenation.
This is not a rotation. The two source ranges can overlap, causing old elements to appear multiple times while other elements disappear. That small detail is where the problem hides the knife.
The answer for starting on day is simply , the first element of the new sequence.
We need a sequence of fixed length supporting:
An implicit treap supplies split(root, k), which returns the first elements and everything after them, and merge(left, right), which concatenates two sequences.
For one value , perform:
The word independently matters. The ranges can overlap, so both must be extracted from the same unchanged version. Consequently, split and merge are persistent: before changing a node's child, they clone that node. Untouched subtrees are shared.
The treap is randomized without storing explicit priorities. When merging trees and , it chooses the root from with probability
and from otherwise, then recursively merges along the boundary. This keeps the expected height logarithmic.
Path copying leaves obsolete nodes in the arena. Also, randomized trees can occasionally acquire an ugly shape—probability is not a legal defense against stack overflow.
After every updates, the implementation:
A rebuild costs and does not change any logical value. There are at most rebuilds under the constraints.
V[a_i..2a_i) + V[0..M-a_i) using persistent splits and a merge.Lemma 1. Every balance relevant to the process belongs to .
Proof. Initially the balance is . For any and , earning produces , while spending produces . Therefore the range is preserved after every day.
Lemma 2. If V represents , then V[a_i..2a_i) + V[0..M-a_i) represents .
Proof. For , day produces , so the new values come from old indices through . For , it produces , so the new values come from old indices through . Concatenating these ranges lists for every in order.
Lemma 3. One treap update constructs exactly the sequence from Lemma 2.
Proof. Persistent splits extract both required ranges from the unchanged old sequence. merge preserves the internal order of both operands and places the second after the first, hence constructs their exact concatenation.
Theorem. Every printed value is the required final balance.
Proof. Initially the sequence is the identity function . Processing days backward, Lemmas 2 and 3 show inductively that after handling day , the sequence represents . Its first element is therefore , the final balance when Monocarp arrives on day . Printing these values for gives answers for suffix lengths .
Let and . Each normal update takes expected time. A rebuild costs , so total expected time is
Under expected logarithmic height, the used arena between rebuilds contains nodes. The implementation pre-reserves a much larger arena to avoid expensive reallocations; the unusually generous memory limit is very much earning its paycheck here.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
constexpr int MX = 200000;
constexpr int REBUILD_EVERY = 5000;
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
struct Node {
int value, cnt, l, r;
Node() : value(0), cnt(0), l(0), r(0) {}
explicit Node(int x) : value(x), cnt(1), l(0), r(0) {}
};
vector<Node> treap(1);
int cnt(int v) {
return v ? treap[v].cnt : 0;
}
void pull(int v) {
treap[v].cnt = cnt(treap[v].l) + cnt(treap[v].r) + 1;
}
int cloneNode(int v) {
treap.push_back(treap[v]);
return int(treap.size()) - 1;
}
int mergeTreap(int l, int r) {
if (!l || !r) return l ? l : r;
int leftSize = cnt(l);
int totalSize = leftSize + cnt(r);
if (rng() % totalSize < leftSize) {
int v = cloneNode(l);
int child = treap[v].r;
treap[v].r = mergeTreap(child, r);
pull(v);
return v;
} else {
int v = cloneNode(r);
int child = treap[v].l;
treap[v].l = mergeTreap(l, child);
pull(v);
return v;
}
}
pair<int, int> splitTreap(int t, int k) {
if (!t) return {0, 0};
int v = cloneNode(t);
int leftSize = cnt(treap[v].l);
if (k <= leftSize) {
int child = treap[v].l;
auto [a, b] = splitTreap(child, k);
treap[v].l = b;
pull(v);
return {a, v};
} else {
int child = treap[v].r;
auto [a, b] = splitTreap(child, k - leftSize - 1);
treap[v].r = a;
pull(v);
return {v, b};
}
}
int prependDay(int root, int x) {
auto [discardedPrefix, tail] = splitTreap(root, x);
auto [middle, discardedSuffix] = splitTreap(tail, x);
auto [prefix, discardedTail] = splitTreap(root, MX - x);
return mergeTreap(middle, prefix);
}
int firstValue(int root) {
while (treap[root].l) root = treap[root].l;
return treap[root].value;
}
int buildBalanced(const vector<int>& values, int l, int r) {
if (l >= r) return 0;
int m = (l + r) / 2;
int left = buildBalanced(values, l, m);
int right = buildBalanced(values, m + 1, r);
treap.emplace_back(values[m]);
int v = int(treap.size()) - 1;
treap[v].l = left;
treap[v].r = right;
pull(v);
return v;
}
int rebuild(int root) {
vector<int> values;
values.reserve(cnt(root));
vector<int> st;
int cur = root;
while (cur || !st.empty()) {
while (cur) {
st.push_back(cur);
cur = treap[cur].l;
}
cur = st.back();
st.pop_back();
values.push_back(treap[cur].value);
cur = treap[cur].r;
}
treap.clear();
treap.emplace_back();
return buildBalanced(values, 0, int(values.size()));
}
int main() {
setIO();
int n;
cin >> n;
vector<int> a(n), ans(n);
for (int& x : a) cin >> x;
treap.reserve(size_t(1ULL << 25) * 3 / 2);
vector<int> identity(MX);
iota(identity.begin(), identity.end(), 0);
int root = buildBalanced(identity, 0, MX);
int iterations = 0;
for (int i = n - 1; i >= 0; --i) {
root = prependDay(root, a[i]);
ans[i] = firstValue(root);
if (++iterations % REBUILD_EVERY == 0) {
root = rebuild(root);
}
}
for (int i = n - 1; i >= 0; --i) {
cout << ans[i] << (i ? ' ' : '\n');
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
constexpr int MX = 200000;
constexpr int REBUILD_EVERY = 5000;
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
struct Node {
int value, cnt, l, r;
Node() : value(0), cnt(0), l(0), r(0) {}
explicit Node(int x) : value(x), cnt(1), l(0), r(0) {}
};
vector<Node> treap(1);
int cnt(int v) {
return v ? treap[v].cnt : 0;
}
void pull(int v) {
treap[v].cnt = cnt(treap[v].l) + cnt(treap[v].r) + 1;
}
int cloneNode(int v) {
treap.push_back(treap[v]);
return int(treap.size()) - 1;
}
int mergeTreap(int l, int r) {
if (!l || !r) return l ? l : r;
int leftSize = cnt(l);
int totalSize = leftSize + cnt(r);
if (rng() % totalSize < leftSize) {
int v = cloneNode(l);
int child = treap[v].r;
treap[v].r = mergeTreap(child, r);
pull(v);
return v;
} else {
int v = cloneNode(r);
int child = treap[v].l;
treap[v].l = mergeTreap(l, child);
pull(v);
return v;
}
}
pair<int, int> splitTreap(int t, int k) {
if (!t) return {0, 0};
int v = cloneNode(t);
int leftSize = cnt(treap[v].l);
if (k <= leftSize) {
int child = treap[v].l;
auto [a, b] = splitTreap(child, k);
treap[v].l = b;
pull(v);
return {a, v};
} else {
int child = treap[v].r;
auto [a, b] = splitTreap(child, k - leftSize - 1);
treap[v].r = a;
pull(v);
return {v, b};
}
}
int prependDay(int root, int x) {
auto [discardedPrefix, tail] = splitTreap(root, x);
auto [middle, discardedSuffix] = splitTreap(tail, x);
auto [prefix, discardedTail] = splitTreap(root, MX - x);
return mergeTreap(middle, prefix);
}
int firstValue(int root) {
while (treap[root].l) root = treap[root].l;
return treap[root].value;
}
int buildBalanced(const vector<int>& values, int l, int r) {
if (l >= r) return 0;
int m = (l + r) / 2;
int left = buildBalanced(values, l, m);
int right = buildBalanced(values, m + 1, r);
treap.emplace_back(values[m]);
int v = int(treap.size()) - 1;
treap[v].l = left;
treap[v].r = right;
pull(v);
return v;
}
int rebuild(int root) {
vector<int> values;
values.reserve(cnt(root));
vector<int> st;
int cur = root;
while (cur || !st.empty()) {
while (cur) {
st.push_back(cur);
cur = treap[cur].l;
}
cur = st.back();
st.pop_back();
values.push_back(treap[cur].value);
cur = treap[cur].r;
}
treap.clear();
treap.emplace_back();
return buildBalanced(values, 0, int(values.size()));
}
int main() {
setIO();
int n;
cin >> n;
vector<int> a(n), ans(n);
for (int& x : a) cin >> x;
treap.reserve(size_t(1ULL << 25) * 3 / 2);
vector<int> identity(MX);
iota(identity.begin(), identity.end(), 0);
int root = buildBalanced(identity, 0, MX);
int iterations = 0;
for (int i = n - 1; i >= 0; --i) {
root = prependDay(root, a[i]);
ans[i] = firstValue(root);
if (++iterations % REBUILD_EVERY == 0) {
root = rebuild(root);
}
}
for (int i = n - 1; i >= 0; --i) {
cout << ans[i] << (i ? ' ' : '\n');
}
return 0;
}