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.
Ignore the zeroing queries first. In the final deletion process, every removed element gets charged once, when it loses to some adjacent element with value at least as large.
For index , not every larger element can delete it. If deletes , then while scanning left from , must be a new record maximum. Equivalently, is on the repeated “nearest previous element with ” chain. Same idea to the right.
So the best static deletion cost for element is . The term matters because the operation pays the cheaper of the two elements, not necessarily the killer. Sneaky little detail.
The only element not charged is the final survivor, which must be a global maximum. If the global maximum is unique, skip its . If there are several global maxima, all are chargeable except the one you keep, so subtract the largest among global maxima.
A zeroing query only turns costs into , never into another positive number. Therefore each is either unchanged or becomes . Precompute the first query time touching or either of its chains, then process removals from the answer by time.
Key Observation
Think about one fixed element . It is removed exactly once. At that moment it is adjacent to some element with , and the paid cost is .
The important question is: which can ever be that neighbor?
Suppose . For and to become adjacent while both are still alive, every element between them must already be gone. If, while moving left from , there is a position between them with value greater than , then that bigger element blocks from being the element that kills . So must be a record maximum while scanning left from .
Those record maxima are exactly this chain:
The right side is symmetric.
So for every index , define:
Then the cheapest possible charge for deleting is
The part is not optional. If itself is cheap, then deleting it next to any valid bigger element costs .
Which element survives?
The last remaining element must have maximum value in the whole array. A non-maximum can never delete a global maximum, because smaller values lose.
If there is a unique global maximum at index , it must survive, so the static answer is
If there are multiple global maxima, exactly one of them survives. Every global maximum can delete another global maximum after the lower stuff between them is cleared, so we choose the survivor that saves the largest charge:
where .
That is the whole static problem. No interval DP circus. Thank god.
Computing the chains
Use a monotonic stack.
For the left chain, scan left to right. Before processing , pop all indices with value strictly smaller than . The stack top, if it exists, is the nearest previous index with value at least .
If that parent is , then the whole left chain of is just plus the left chain of . Therefore:
Do the same scan from right to left for .
Now handle zeroing
Let be the query number when index becomes zero.
For an index , its contribution becomes as soon as any of these indices is zeroed:
So define a death time:
For query count , contribution is still alive iff .
We compute the chain minimum query times using the exact same stack DP as costs:
Then sweep :
total = sum of all currently alive contributions;A max-heap over global maxima handles that last part.
Complexity
Each test case is because of the heap. The stack work is linear. The memory usage is .
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
const ll INF = (1LL << 62);
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<ll> a(n), c(n);
for (ll &x : a) cin >> x;
for (ll &x : c) cin >> x;
vector<int> pos(n);
for (int t = 1; t <= n; t++) {
int x;
cin >> x;
--x;
pos[x] = t;
}
vector<ll> leftCost(n, INF), rightCost(n, INF);
vector<int> leftTime(n, n + 1), rightTime(n, n + 1);
vector<int> st;
st.reserve(n);
for (int i = 0; i < n; i++) {
while (!st.empty() && a[st.back()] < a[i]) st.pop_back();
if (!st.empty()) {
int p = st.back();
leftCost[i] = min(c[p], leftCost[p]);
leftTime[i] = min(pos[p], leftTime[p]);
}
st.push_back(i);
}
st.clear();
for (int i = n - 1; i >= 0; i--) {
while (!st.empty() && a[st.back()] < a[i]) st.pop_back();
if (!st.empty()) {
int p = st.back();
rightCost[i] = min(c[p], rightCost[p]);
rightTime[i] = min(pos[p], rightTime[p]);
}
st.push_back(i);
}
ll mx = *max_element(a.begin(), a.end());
int maxCount = 0, onlyMax = -1;
for (int i = 0; i < n; i++) {
if (a[i] == mx) {
maxCount++;
onlyMax = i;
}
}
bool multiMax = maxCount > 1;
vector<ll> die(n + 2, 0);
priority_queue<pair<ll, int>> maxHeap;
ll total = 0;
for (int i = 0; i < n; i++) {
if (!multiMax && i == onlyMax) continue;
ll w = min(c[i], min(leftCost[i], rightCost[i]));
int death = min(pos[i], min(leftTime[i], rightTime[i]));
total += w;
die[death] += w;
if (multiMax && a[i] == mx) {
maxHeap.push({w, death});
}
}
for (int q = 0; q <= n; q++) {
while (!maxHeap.empty() && maxHeap.top().second <= q) {
maxHeap.pop();
}
ll savedRoot = 0;
if (multiMax && !maxHeap.empty()) savedRoot = maxHeap.top().first;
if (q) cout << ' ';
cout << total - savedRoot;
if (q < n) total -= die[q + 1];
}
cout << '\n';
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
const ll INF = (1LL << 62);
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<ll> a(n), c(n);
for (ll &x : a) cin >> x;
for (ll &x : c) cin >> x;
vector<int> pos(n);
for (int t = 1; t <= n; t++) {
int x;
cin >> x;
--x;
pos[x] = t;
}
vector<ll> leftCost(n, INF), rightCost(n, INF);
vector<int> leftTime(n, n + 1), rightTime(n, n + 1);
vector<int> st;
st.reserve(n);
for (int i = 0; i < n; i++) {
while (!st.empty() && a[st.back()] < a[i]) st.pop_back();
if (!st.empty()) {
int p = st.back();
leftCost[i] = min(c[p], leftCost[p]);
leftTime[i] = min(pos[p], leftTime[p]);
}
st.push_back(i);
}
st.clear();
for (int i = n - 1; i >= 0; i--) {
while (!st.empty() && a[st.back()] < a[i]) st.pop_back();
if (!st.empty()) {
int p = st.back();
rightCost[i] = min(c[p], rightCost[p]);
rightTime[i] = min(pos[p], rightTime[p]);
}
st.push_back(i);
}
ll mx = *max_element(a.begin(), a.end());
int maxCount = 0, onlyMax = -1;
for (int i = 0; i < n; i++) {
if (a[i] == mx) {
maxCount++;
onlyMax = i;
}
}
bool multiMax = maxCount > 1;
vector<ll> die(n + 2, 0);
priority_queue<pair<ll, int>> maxHeap;
ll total = 0;
for (int i = 0; i < n; i++) {
if (!multiMax && i == onlyMax) continue;
ll w = min(c[i], min(leftCost[i], rightCost[i]));
int death = min(pos[i], min(leftTime[i], rightTime[i]));
total += w;
die[death] += w;
if (multiMax && a[i] == mx) {
maxHeap.push({w, death});
}
}
for (int q = 0; q <= n; q++) {
while (!maxHeap.empty() && maxHeap.top().second <= q) {
maxHeap.pop();
}
ll savedRoot = 0;
if (multiMax && !maxHeap.empty()) savedRoot = maxHeap.top().first;
if (q) cout << ' ';
cout << total - savedRoot;
if (q < n) total -= die[q + 1];
}
cout << '\n';
}
}