题意:n个数排成一列,每次选择序列中的最小值(如果有多个,取原始位置最小的),把它和它前面的所有数翻转,然后把这个数从序列中删去。输出每次选择的最小值的下标。
思路:
* Splay Tree是一棵平衡树,在平衡的基础上加上独有的伸展操作,Splay能快速实现诸如区间翻转,区间切割等等普通数据结构力不从心的操作。一棵二叉树,如果用作数据检索,会把数据作为key,中序遍历后得到全部数据的有序排列,而Splay在解决区间问题时,会以数据的下标作为key,中序遍历为数据本来的顺序。在此基础上,伸展操作将不会改变数据本来的顺序,而能达到将一个区间的数据”搬到“一棵子树上的目的,然后对子树进行操作即可。
* 这个题的思路就应该很清晰了,每个节点需要维护几个东西,包括size、子树的最小值的索引、是否翻转、值、原始位置以及parent、两个son的索引。每次找到最小值 V 后,把它splay到根,根据它的左子树的大小可以得到最小值下标,然后找比它大的最小值splay到根,删掉最小值 V ,把标记放到它的左儿子上,该更新的都要更新。标记采用延迟标记法,跟线段树一样。
#include <bits/stdc++.h>
using namespace std;
#ifndef ONLINE_JUDGE
#include "local.h"
#endif // ONLINE_JUDGE
#define pb(x) push_back(x)
#define mp(x, y) make_pair(x, y)
#define all(a) (a).begin(), (a).end()
#define mset(a, x) memset(a, x, sizeof(a))
#define mcpy(a, b) memcpy(a, b, sizeof(b))
#define up(a, b) for (int a = 0; a < (b); a ++)
#define down(a, b) for (int a = b - 1; (a) >= 0; a --)
#define rep(i, a, b) for (int i = a; i <= (b); i ++)
#define rrep(i, a, b) for (int i = a; i >= (b); i --)
#define cas() int T, cas = 0; cin >> T; while (T --)
#define printCas(ch) printf("Case #%d:%c", ++ cas, ch)
#define watch(ele) cout << ele << endl
#define in(a) scanf("%d", &a)
typedef long long ll;
typedef pair<int, int> pii;
template<typename T>bool umax(T&a, const T&b){return a<b?(a=b,true):false;}
template<typename T>bool umin(T&a, const T&b){return b<a?(a=b,true):false;}
const int N = 1e5 + 7;
#define ls s[0]
#define rs s[1]
struct Node {
int v, index, sz, flip;
Node *f, *s[2], *minn;
};
Node node[N], *root;
int cnt;
Node* newNode(int v, int index, Node *f) {
Node *o = node + cnt ++;
o->v = v;
o->index = index;
o->ls = o->rs = 0;
o->f = f;
o->minn = o;
o->sz = 1;
o->flip = 0;
return o;
}
void flip(Node *o) {
o->flip ^= 1;
swap(o->ls, o->rs);
}
bool smaller(Node *a, Node *b) {
return a->v == b->v? a->index < b->index : a->v < b->v;
}
void pushup(Node *o) {
o->sz = 1;
if (o->ls) o->sz += o->ls->sz;
if (o->rs) o->sz += o->rs->sz;
o->minn = o;
if (o->ls && smaller(o->ls->minn, o->minn)) o->minn = o->ls->minn;
if (o->rs && smaller(o->rs->minn, o->minn)) o->minn = o->rs->minn;
}
void pushdown(Node *o) {
if (o->flip == 0) return;
if (o->ls) flip(o->ls);
if (o->rs) flip(o->rs);
o->flip = 0;
}
int dir(Node *o) {
return o->f->rs == o;
}
void rotate(Node *o) {
int diro = dir(o);
Node *f = o->f;
if (o->s[diro ^ 1]) o->s[diro ^ 1]->f = f;
f->s[diro] = o->s[diro ^ 1];
if (f->f) {
if (f->f->ls == f) f->f->s[0] = o;
else f->f->s[1] = o;
}
o->f = f->f;
f->f = o;
o->s[diro ^ 1] = f;
pushup(f);
pushup(o);
}
void splay(Node *o) {
while (o->f) {
if (o->f->f && dir(o) == dir(o->f)) rotate(o->f);
rotate(o);
}
root = o;
}
void insert(int v, int index) {
Node *o = root;
if (!root) root = newNode(v, index, 0);
else splay(root->rs = newNode(v, index, root));
}
void findMin() {
Node *o = root;
while (o->minn != o) {
pushdown(o);
if (o->ls && o->minn == o->ls->minn) o = o->ls;
else o = o->rs;
}
pushdown(o);
splay(o);
}
void findNext() {
Node *o = root->rs;
while (o->ls) {
pushdown(o);
o = o->ls;
}
pushdown(o);
splay(o);
}
int go() {
findMin();
Node *o = root;
findNext();
if (o->ls) o->ls->f = root;
root->ls = o->ls;
if (o->ls) flip(o->ls);
pushup(root);
return o->ls? o->ls->sz : 0;
}
int n, a[N];
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
while (cin >> n, n) {
up(i, n) in(a[i]);
root = 0;
cnt = 0;
up(i, n) insert(a[i], i);
insert(1 << 30, n);
up(i, n) printf("%d%c", i + 1 + go(), i == n - 1? '\n' : ' ');
}
return 0;
}