题意:给出一段序列,每次找出第i的大的数与它本来的位置一段序列进行反转, 相当于一次排序,每次输出第i大的数的位置。
思路:相当于区间的反转,我们对于整个序列建立一棵伸展树,每次把第i大的数字旋转到根,其的左孩子个数就相当于它在原序列的位置,然后每次进行区间反转,splay的区间操作会在另一篇文章中提到,其他的操作与线段树的一致。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define N 500006
#define INF 0x3f3f3f3f
#define lc (tr[id].c[0])
#define rc (tr[id].c[1])
#define KEY tr[tr[root].c[1]].c[0]
int data[N/5];
struct Num {
int val, id;
bool operator<(const Num a)const {
if (val == a.val) return id < a.id;
return val < a.val;
}
}So[N/5];
struct Tr
{
int fa, sum, val, c[2], lz;
}tr[N];
int tot, root, n;
int newtr(int k, int f, int pos) {
tr[tot].sum = 1, tr[tot].val = k;
tr[tot].c[0] = tr[tot].c[1] = -1;
tr[tot].lz = 0;
tr[tot].fa = f;
return tot++;
}
void Push(int id) {
// if (id == -1) return;
int lsum, rsum;
lsum = (lc == -1)?0:tr[lc].sum;
rsum = (rc == -1)?0:tr[rc].sum;
tr[id].sum = lsum+rsum+1;
}
int build(int l, int r, int f) {
if (r < l) return-1;
int mid = l+r>>1;
int ro = newtr(mid, f, mid);
data[mid] = ro;
tr[ro].c[0] = build(l, mid-1, ro);
tr[ro].c[1] = build(mid+1, r, ro);
Push(ro);
return ro;
}
void lazy(int id) {
// if (id == -1) return;
if (tr[id].lz) {
swap(lc, rc);
tr[lc].lz ^= 1, tr[rc].lz ^= 1;
tr[id].lz = 0;
}
}
void Rotate(int x, int k) {
if (tr[x].fa == -1) return;
int fa = tr[x].fa, w;
lazy(fa), lazy(x);
tr[fa].c[!k] = tr[x].c[k];
if (tr[x].c[k] != -1) tr[tr[x].c[k]].fa = fa;
tr[x].fa = tr[fa].fa, tr[x].c[k] = fa;
if (tr[fa].fa != -1) {
w = tr[tr[fa].fa].c[1]==fa;
tr[tr[fa].fa].c[w] = x;
}
tr[fa].fa = x;
Push(fa);
Push(x);
}
void Splay(int x, int goal) {
if (x == -1) return;
lazy(x);
while (tr[x].fa != goal) {
int y = tr[x].fa;
lazy(tr[y].fa), lazy(y), lazy(x);
bool w = x==tr[y].c[1];
if (tr[y].fa != goal && w == (y==tr[tr[y].fa].c[1]))
Rotate(y, !w);
Rotate(x, !w);
}
if (goal == -1) root = x;
Push(x);
}
int find(int k) {
int id = root;
while (id != -1) {
lazy(id);
int lsum = (lc==-1)?0:tr[lc].sum;
if (lsum >= k) {
id = lc;
}
else if (lsum+1 == k) break;
else {
k = k-lsum-1;
id = rc;
}
}
return id;
}
int Getnext(int id) {
lazy(id);
int p = tr[id].c[1];
if (p == -1) return id;
lazy(p);
while (tr[p].c[0] != -1) {
p = tr[p].c[0];
lazy(p);
}
return p;
}
int main() {
int m, l, r, k, d, i;
while (~scanf("%d", &n), n) {
for (i = 1;i <= n;i++) {
scanf("%d", &So[i].val);
So[i].id = i;
}
sort(So+1, So+n+1);
So[0].id = 0;
tot = 0;
root = build(0, n+1, -1);
for (i = 1;i <= n;i++) {
int ro = data[So[i].id], ne;
Splay(ro, -1);
d = tr[tr[root].c[0]].sum;
l = data[So[i-1].id];
ne = Getnext(ro);
Splay(l, -1), Splay(ne, root);
lazy(root), lazy(tr[root].c[1]);
tr[KEY].lz ^= 1;
if (i != 1) printf(" ");
printf("%d", d);
}
puts("");
}
}