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.
A left-to-right greedy choice is bait. An unknown value can satisfy the current prefix count and still steal a value/rank needed by a fixed p later.
Flip the statistic. Instead of inversions, use , the number of increasing pairs in the prefix. For a last element, the increase in is just the number of previous elements smaller than it.
Build the permutation from right to left. When an element is removed, the remaining values can be re-ranked, but all earlier prefix inversion counts stay unchanged because relative order inside every earlier prefix stays the same.
Between two consecutive s positions , every position is a fixed p. So when solving for , those fixed values form a known block; only the earlier prefix and itself are unknown.
For the block between and , scan it from right to left with a Fenwick tree. If and is the current count of alive values smaller than fixed , then becomes the weighted rank of : earlier values have weight , block values have weight . A weighted kth query gives .
Front-to-back greedy is the trap here. Picking some value that satisfies the current prefix can easily wreck a future fixed p, so we solve the permutation backwards.
Define
.
So is the number of increasing pairs inside prefix . This is nicer than inversions because if position is currently the last remaining position, then the new contribution of is exactly the number of previous elements smaller than .
The reverse operation is clean: once we decide the last element, delete it. Values greater than it would all decrease by in the smaller permutation, but prefix inversion counts before it do not change, because relative order inside those prefixes does not change. We do not actually mutate all values. Instead, keep a Fenwick tree over original labels that tells us which values are still alive. Ranks among alive values behave exactly like the decreased values would.
Now process only the positions marked s, from right to left.
Let r be the current s position, and let l be the previous s position, or if there is none. The positions are all fixed p positions; call this block . Before processing r, our Fenwick tree contains exactly the values used in prefix , each with weight . Any fixed suffix after the last s was deleted before the loop starts.
Let , let be the first positions, and let . Also let
.
This counts all increasing pairs whose right endpoint is in or at position .
We scan the fixed block from right to left. When we are at a fixed position , all fixed block positions to its right have already been deleted from the Fenwick tree. So
counts the real increasing-pair contribution of position , plus one possible fake extra count: the unknown value , if . Therefore, after summing all these queries into ,
.
The contribution of itself is
,
where is the number of values in smaller than , and is the number of values in smaller than . Since every block value is either smaller or greater than ,
.
That is the whole trick. After the scan, the Fenwick tree contains the earlier prefix and the unknown value with weight , while the fixed block has weight . Temporarily add weight to every value in . Now the total weight strictly below is exactly
.
Since itself still has weight , the value at zero-based weighted rank is exactly . Find it with a Fenwick kth query, store it as , undo the temporary weights, and delete .
The invariant is then restored for the previous s position: the Fenwick tree contains exactly the values of the remaining prefix. No backtracking, no guessing, no nonsense.
Edge cases:
s position, every value is directly fixed; output them.s position, use and .s are deleted before processing starts.Each fixed position is touched only inside its own segment, and each s position does one kth query. So the complexity is per test case, with memory.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct Fenwick {
int n = 0;
vector<int> bit;
Fenwick() = default;
Fenwick(int n_) { init(n_); }
void init(int n_) {
n = n_;
bit.assign(n + 1, 0);
}
void add(int idx, int delta) {
for (; idx <= n; idx += idx & -idx) bit[idx] += delta;
}
int sumPrefix(int idx) const {
int res = 0;
for (; idx > 0; idx -= idx & -idx) res += bit[idx];
return res;
}
int kth(ll k) const {
int idx = 0;
int step = 1;
while ((step << 1) <= n) step <<= 1;
for (; step; step >>= 1) {
int nxt = idx + step;
if (nxt <= n && bit[nxt] <= k) {
idx = nxt;
k -= bit[nxt];
}
}
return idx + 1;
}
};
int main() {
setIO();
int tc;
cin >> tc;
while (tc--) {
int n;
cin >> n;
vector<char> type(n + 1);
vector<ll> inc(n + 1, 0);
vector<int> ans(n + 1, 0), lastS(n + 1, 0);
for (int i = 1; i <= n; ++i) {
ll x;
cin >> type[i] >> x;
if (type[i] == 'p') {
ans[i] = (int)x;
} else {
inc[i] = 1LL * i * (i - 1) / 2 - x;
}
}
for (int i = 1; i <= n; ++i) {
lastS[i] = (type[i] == 's' ? i : lastS[i - 1]);
}
Fenwick fw(n);
for (int value = 1; value <= n; ++value) fw.add(value, 1);
int last = lastS[n];
for (int i = last + 1; i <= n; ++i) fw.add(ans[i], -1);
for (int r = last; r > 0; r = lastS[r - 1]) {
int l = lastS[r - 1];
ll rank = inc[r] - inc[l];
for (int j = r - 1; j > l; --j) {
rank -= fw.sumPrefix(ans[j] - 1);
fw.add(ans[j], -1);
}
rank += r - l - 1;
for (int j = r - 1; j > l; --j) fw.add(ans[j], 2);
ans[r] = fw.kth(rank);
for (int j = r - 1; j > l; --j) fw.add(ans[j], -2);
fw.add(ans[r], -1);
}
for (int i = 1; i <= n; ++i) {
if (i > 1) cout << ' ';
cout << ans[i];
}
cout << '\n';
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct Fenwick {
int n = 0;
vector<int> bit;
Fenwick() = default;
Fenwick(int n_) { init(n_); }
void init(int n_) {
n = n_;
bit.assign(n + 1, 0);
}
void add(int idx, int delta) {
for (; idx <= n; idx += idx & -idx) bit[idx] += delta;
}
int sumPrefix(int idx) const {
int res = 0;
for (; idx > 0; idx -= idx & -idx) res += bit[idx];
return res;
}
int kth(ll k) const {
int idx = 0;
int step = 1;
while ((step << 1) <= n) step <<= 1;
for (; step; step >>= 1) {
int nxt = idx + step;
if (nxt <= n && bit[nxt] <= k) {
idx = nxt;
k -= bit[nxt];
}
}
return idx + 1;
}
};
int main() {
setIO();
int tc;
cin >> tc;
while (tc--) {
int n;
cin >> n;
vector<char> type(n + 1);
vector<ll> inc(n + 1, 0);
vector<int> ans(n + 1, 0), lastS(n + 1, 0);
for (int i = 1; i <= n; ++i) {
ll x;
cin >> type[i] >> x;
if (type[i] == 'p') {
ans[i] = (int)x;
} else {
inc[i] = 1LL * i * (i - 1) / 2 - x;
}
}
for (int i = 1; i <= n; ++i) {
lastS[i] = (type[i] == 's' ? i : lastS[i - 1]);
}
Fenwick fw(n);
for (int value = 1; value <= n; ++value) fw.add(value, 1);
int last = lastS[n];
for (int i = last + 1; i <= n; ++i) fw.add(ans[i], -1);
for (int r = last; r > 0; r = lastS[r - 1]) {
int l = lastS[r - 1];
ll rank = inc[r] - inc[l];
for (int j = r - 1; j > l; --j) {
rank -= fw.sumPrefix(ans[j] - 1);
fw.add(ans[j], -1);
}
rank += r - l - 1;
for (int j = r - 1; j > l; --j) fw.add(ans[j], 2);
ans[r] = fw.kth(rank);
for (int j = r - 1; j > l; --j) fw.add(ans[j], -2);
fw.add(ans[r], -1);
}
for (int i = 1; i <= n; ++i) {
if (i > 1) cout << ' ';
cout << ans[i];
}
cout << '\n';
}
}