[CQOI2014]排序机械臂


\(Solution\)

非常板的一道题,支持区间翻转
本人采用 \(\text{FQH-Treap}\) 实现,按排名分裂
题目显然可以转化为找区间最小值的位置,只要每次把当前最小值扔出 \(\text{Treap}\)
为处理最小值相同的情况,就离散化处理
然后维护子树最小值就对了

\(\text{Code}\)

#include 
#include 
#include 
#define re register
using namespace std;
typedef long long LL;

const int N = 1e5 + 5;
int n, b[N], rt, ls[N], rs[N], val[N], mi[N], rnd[N], siz[N], tag[N];
struct nod{int v, id;}a[N];
inline bool cmp(nod a, nod b){return (a.v < b.v ? 1 : (a.v == b.v ? a.id < b.id : 0));}

inline int new_node(int x)
{
	static int size = 0;
	val[++size] = x, mi[size] = x, rnd[size] = rand(),
	siz[size] = 1, ls[size] = rs[size] = tag[size] = 0;
	return size;
}

inline void pushup(int p)
{
	siz[p] = siz[ls[p]] + siz[rs[p]] + 1, mi[p] = val[p];
	if (ls[p]) mi[p] = min(mi[p], mi[ls[p]]);
	if (rs[p]) mi[p] = min(mi[p], mi[rs[p]]);
}

inline void pushdown(int p)
{
	if (!p || !tag[p]) return;
	tag[p] = 0, swap(ls[p], rs[p]);
	if (ls[p]) tag[ls[p]] ^= 1;
	if (rs[p]) tag[rs[p]] ^= 1;
}

void split(int p, int k, int &x, int &y)
{
	if (!p) return void(x = y = 0);
	pushdown(p);
	if (k <= siz[ls[p]]) y = p, split(ls[p], k, x, ls[y]);
	else x = p, split(rs[p], k - siz[ls[p]] - 1, rs[x], y);
	pushup(p);
}

int merge(int x, int y)
{
	if (!x || !y) return x | y;
	pushdown(x), pushdown(y);
	if (rnd[x] < rnd[y]){rs[x] = merge(rs[x], y), pushup(x); return x;}
	ls[y] = merge(x, ls[y]), pushup(y); return y;
}

inline int find(int p)
{
	int k = 1;
	while (1)
	{
		pushdown(p);
		if (ls[p] && mi[ls[p]] == mi[p]) p = ls[p];
		else if (rs[p] && mi[rs[p]] == mi[p]) k += siz[ls[p]] + 1, p = rs[p];
		else return k + siz[ls[p]];
	}
}

int main()
{
	srand((unsigned)time(NULL));
	scanf("%d", &n);
	for(re int i = 1; i <= n; i++) scanf("%d", &a[i].v), a[i].id = i;
	sort(a + 1, a + n + 1, cmp);
	for(re int i = 1; i <= n; i++) b[a[i].id] = i;
	for(re int i = 1; i <= n; i++) rt = merge(rt, new_node(b[i]));
	for(re int i = 1; i <= n; i++)
	{
		int x, y, z, o = find(rt);
		printf("%d ", o + i - 1);
		split(rt, o, x, y), split(x, o - 1, x, z);
		tag[x] ^= 1, rt = merge(x, y);
	}
}