题目大意:一串数字,使用如下方式排序: 先找到最小的数的位置$P_1$,将区间$[1,P_1]$反转,再找到第二小的数的位置$P_2$,将区间$[2,P_2]$反转,知道排序完成。输出每次操作的$P_i$,要求稳定排序(在括号外的是多组数据,括号内的是单组数据,四倍经验)
题解:可以用平衡数维护序列,只要维护求一个数的位置和区间翻转即可
卡点:查询位置时未$pushdown$
C++ Code:
#include <cstdio> #include <algorithm> #define maxn 100010 int n; int s[maxn], rnk[maxn], mp[maxn]; inline bool cmp(int a, int b) { if (s[a] == s[b]) return a < b; return s[a] < s[b]; } namespace Treap { int rc[maxn], lc[maxn], pri[maxn], V[maxn], sz[maxn]; int fa[maxn], tg[maxn]; int root, idx, ta, tb, tmp, res; int seed = 20040826; inline int rand() {return seed *= 48271;} inline int nw(int x) { V[++idx] = x; sz[idx] = 1; pri[idx] = rand(); lc[idx] = rc[idx] = fa[idx] = tg[idx] = 0; return idx; } inline int update(int rt) { sz[rt] = sz[lc[rt]] + sz[rc[rt]] + 1; fa[lc[rt]] = fa[rc[rt]] = rt; return rt; } inline void pushdown(int rt) { if (tg[rt]) { tg[rt] = 0; std::swap(lc[rt], rc[rt]); tg[lc[rt]] ^= 1, tg[rc[rt]] ^= 1; } } void split(int rt, int k, int &x, int &y) { if (!rt) x = y = 0; else { pushdown(rt); if (sz[lc[rt]] < k) split(rc[rt], k - sz[lc[rt]] - 1, rc[rt], y), x = update(rt); else split(lc[rt], k, x, lc[rt]), y = update(rt); } } int merge(int x, int y) { if (!x || !y) return x | y; pushdown(x), pushdown(y); if (pri[x] < pri[y]) {rc[x] = merge(rc[x], y); return update(x);} else {lc[y] = merge(x, lc[y]); return update(y);} } void debug(int rt) { if (lc[rt]) debug(lc[rt]); printf("%d ", V[rt]); if (rc[rt]) debug(rc[rt]); } inline void insert(int x) { if (!root) root = nw(x); else root = merge(root, nw(x)); } int S[maxn], top; inline int gtrnk(int x) { top = 0; for (int i = x; i; i = fa[i]) S[++top] = i; for (; top; top--) pushdown(S[top]); res = sz[lc[x]] + 1; while (fa[x]) { if (rc[fa[x]] == x) res += sz[lc[fa[x]]] + 1; x = fa[x]; } return res; } inline void reverse(int l, int r) { if (l > r) std::swap(l, r); split(root, r, tmp, tb); split(tmp, l - 1, ta, tmp); tg[tmp] ^= 1; root = merge(ta, merge(tmp, tb)); } inline void clear() { idx = root = 0; } } int main() { scanf("%d", &n); while (true) { if (!n) break; for (int i = 1; i <= n; i++) { scanf("%d", s + i); rnk[i] = i; } std::sort(rnk + 1, rnk + n + 1, cmp); for (int i = 1; i <= n; i++) mp[rnk[i]] = i; for (int i = 1; i <= n; i++) Treap::insert(s[i]); for (int I = 1, i = rnk[I]; I <= n; i = rnk[++I]) { int res = Treap::gtrnk(i); printf("%d", res); putchar(I == n ? ' ' : ' '); Treap::reverse(I, res); } scanf("%d", &n); if (n) { Treap::clear(); } } return 0; }