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.
For a subarray , don’t stare directly at the MEX. Pick any missing value instead, and look at .
If is missing from , then , so . That means the real weight is the maximum over all missing .
Now fix the right endpoint and a value . To keep missing in , must be after the last occurrence of before or at .
For fixed and , the best such is exactly , because moving left can only add more elements greater than , never remove them.
Maintain for every . When a new value arrives, add to all , reset , and take the global maximum with a lazy segment tree.
The obvious-looking route is: “for every suffix, maintain its MEX, then count bigger elements.” That path is pain. Don’t do that.
Instead, define for any subarray and any value missing from :
The weight of is
Now here is the whole trick: among all missing values , the best one is always the MEX.
Why? If is missing, then by definition
So every element greater than is also greater than , meaning
Since the MEX itself is missing, we get:
So we can stop explicitly tracking MEX. Huge win.
We need the answer for every right endpoint :
Using the rewrite above, this becomes:
Now fix some value .
Let be the last position where appears among . If never appeared, set .
For to be missing from , we must have
Among all such , which one maximizes the count of elements greater than ?
The earliest one:
Because moving to the right only deletes elements. Deleted elements might be useless, but they might also be greater than ; either way, the count cannot increase. So for each , the best subarray ending at with missing is forced:
Define
Then the answer for right endpoint is simply
That’s the entire problem. Everything else is just maintaining this array without doing dumb stuff.
Suppose we process the array left to right, and the new value is
What happens to ?
For , the new element satisfies , so it contributes to .
For , the new element does not satisfy , so does not change.
For , the new element is an occurrence of itself. That means becomes , so the interval becomes empty. Therefore:
So every step does exactly this:
That is screaming “lazy segment tree”: range add, point assign, global max.
The array values satisfy .
For any subarray of length at most , its MEX is at most . So tracking is enough.
The value is useful as a harmless sentinel. It never gets positive contribution from any element, since no array value is greater than , but it keeps the indexing clean.
We prove that the algorithm outputs the required value for every right endpoint .
First, for any subarray , its weight equals
The MEX is missing, so the maximum is at least the weight. For any other missing , we have , so the number of elements greater than is at most the number of elements greater than the MEX. Thus the maximum is exactly the weight.
Now fix a right endpoint and a value . A subarray ending at has missing iff its left endpoint satisfies . Among all such , choosing maximizes the number of elements greater than , because it includes every possible element that could contribute. Therefore the best value for this fixed is exactly
Taking the maximum over all gives the best weight among all subarrays ending at .
Finally, the update rules maintain these values exactly. When arrives, it contributes to precisely those . For , the latest occurrence moves to , so becomes . For , nothing changes. Thus after each update, the segment tree stores the correct values, and its maximum is the required answer.
Each element causes one range add, one point assignment, and one global maximum query.
So the complexity is
per test case, with memory. Clean, fast, no MEX gymnastics circus.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct SegTree {
int n;
vector<int> mx, lazy;
SegTree(int sz = 0) {
init(sz);
}
void init(int sz) {
n = 1;
while (n < sz) n <<= 1;
mx.assign(2 * n, 0);
lazy.assign(2 * n, 0);
}
void apply(int p, int v) {
mx[p] += v;
lazy[p] += v;
}
void push(int p) {
if (lazy[p] == 0) return;
apply(p << 1, lazy[p]);
apply(p << 1 | 1, lazy[p]);
lazy[p] = 0;
}
void range_add(int ql, int qr, int v, int p, int l, int r) {
if (qr < l || r < ql) return;
if (ql <= l && r <= qr) {
apply(p, v);
return;
}
push(p);
int m = (l + r) >> 1;
range_add(ql, qr, v, p << 1, l, m);
range_add(ql, qr, v, p << 1 | 1, m + 1, r);
mx[p] = max(mx[p << 1], mx[p << 1 | 1]);
}
void range_add(int l, int r, int v) {
if (l <= r) range_add(l, r, v, 1, 0, n - 1);
}
void point_set(int idx, int val, int p, int l, int r) {
if (l == r) {
mx[p] = val;
lazy[p] = 0;
return;
}
push(p);
int m = (l + r) >> 1;
if (idx <= m) point_set(idx, val, p << 1, l, m);
else point_set(idx, val, p << 1 | 1, m + 1, r);
mx[p] = max(mx[p << 1], mx[p << 1 | 1]);
}
void point_set(int idx, int val) {
point_set(idx, val, 1, 0, n - 1);
}
int all_max() const {
return mx[1];
}
};
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
SegTree seg(n + 1);
for (int i = 0; i < n; i++) {
int x;
cin >> x;
seg.range_add(0, x - 1, 1);
seg.point_set(x, 0);
cout << seg.all_max() << (i + 1 == n ? '\n' : ' ');
}
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct SegTree {
int n;
vector<int> mx, lazy;
SegTree(int sz = 0) {
init(sz);
}
void init(int sz) {
n = 1;
while (n < sz) n <<= 1;
mx.assign(2 * n, 0);
lazy.assign(2 * n, 0);
}
void apply(int p, int v) {
mx[p] += v;
lazy[p] += v;
}
void push(int p) {
if (lazy[p] == 0) return;
apply(p << 1, lazy[p]);
apply(p << 1 | 1, lazy[p]);
lazy[p] = 0;
}
void range_add(int ql, int qr, int v, int p, int l, int r) {
if (qr < l || r < ql) return;
if (ql <= l && r <= qr) {
apply(p, v);
return;
}
push(p);
int m = (l + r) >> 1;
range_add(ql, qr, v, p << 1, l, m);
range_add(ql, qr, v, p << 1 | 1, m + 1, r);
mx[p] = max(mx[p << 1], mx[p << 1 | 1]);
}
void range_add(int l, int r, int v) {
if (l <= r) range_add(l, r, v, 1, 0, n - 1);
}
void point_set(int idx, int val, int p, int l, int r) {
if (l == r) {
mx[p] = val;
lazy[p] = 0;
return;
}
push(p);
int m = (l + r) >> 1;
if (idx <= m) point_set(idx, val, p << 1, l, m);
else point_set(idx, val, p << 1 | 1, m + 1, r);
mx[p] = max(mx[p << 1], mx[p << 1 | 1]);
}
void point_set(int idx, int val) {
point_set(idx, val, 1, 0, n - 1);
}
int all_max() const {
return mx[1];
}
};
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
SegTree seg(n + 1);
for (int i = 0; i < n; i++) {
int x;
cin >> x;
seg.range_add(0, x - 1, 1);
seg.point_set(x, 0);
cout << seg.all_max() << (i + 1 == n ? '\n' : ' ');
}
}
return 0;
}