SP2059 CERC07S - Robotic Sort 题解
题目要求我们对一个序列进行一系列反转操作,使得这个序列最终有序。
对于第
说到区间反转,我们就可以想到使用 Splay。
这样就可以借鉴文艺平衡树的思路了。
我们每一次查询一个权值所对应的节点。找到我们需要反转的区间之后,将其左端点的前驱旋至根,然后将其右端点的后继旋至左端点前驱的下面,这样就拎出来了整个区间了。
然后直接打反转标记即可。
但是我们还有一个问题。就是题目给出的序列是无序的,我们还需要自己排序。
同时题目还要求我们做到稳定的排序。也就是两个物品如果高度相等,排序后它们的相对位置关系需要与初始时相同。
那么我们拿一个结构体记录一下每一个物品的高度和一开始的位置,然后按照权值排序。
然后我们再建立一颗 Splay,像上面说的那样维护、反转区间就可以了。
同时题目要求输出第
这里我向序列中加入了两个哨兵节点,这样会使左子树的大小增加 1,直接输出左子树的大小就可以了。
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 100010;
const int INF = 1e8;
int n, m;
struct Node
{
int s[2], fa;
int v, sz;
int flag;
};
Node tr[N];
int rt;
void maintain(int p)
{
tr[p].sz = tr[tr[p].s[0]].sz + tr[tr[p].s[1]].sz + 1;
}
void pushdown(int p)
{
if(tr[p].flag)
{
if(tr[p].s[0])tr[tr[p].s[0]].flag ^= 1;
if(tr[p].s[1])tr[tr[p].s[1]].flag ^= 1;
swap(tr[p].s[0], tr[p].s[1]);
tr[p].flag = 0;
}
}
void rotate(int x)
{
int y = tr[x].fa, z = tr[y].fa;
int k = (tr[y].s[1] == x) ? 1 : 0;
tr[z].s[tr[z].s[1] == y] = x, tr[x].fa = z;
tr[y].s[k] = tr[x].s[k ^ 1], tr[tr[x].s[k ^ 1]].fa = y;
tr[x].s[k ^ 1] = y, tr[y].fa = x;
maintain(y); maintain(x);
}
void splay(int x, int k)
{
while(tr[x].fa != k)
{
int y = tr[x].fa, z = tr[y].fa;
pushdown(z), pushdown(y), pushdown(x);
if(z != k)
{
if((tr[y].s[1] == x) ^ (tr[z].s[1] == y)) rotate(x);
else rotate(y);
}
rotate(x);
}
if(!k)rt = x;
}
void build(int &p, int l, int r)
{
if(l > r)return;
int mid = (l + r) >> 1;
p = mid;
if(l == r)
{
tr[p].sz = 1;
return;
}
if(l < mid)
{
build(tr[p].s[0], l, mid - 1);
tr[tr[p].s[0]].fa = p;
}
if(r > mid)
{
build(tr[p].s[1], mid + 1, r);
tr[tr[p].s[1]].fa = p;
}
maintain(p);
}
int get_k(int k)
{
int p = rt;
while(true)
{
pushdown(p);
if(tr[tr[p].s[0]].sz >= k && tr[p].s[0])p = tr[p].s[0];
else
{
k -= tr[tr[p].s[0]].sz + 1;
if(k == 0)return p;
else p = tr[p].s[1];
}
}
}
struct TBS
{
int x, pos;
bool operator < (const TBS &a)const
{
return (x == a.x) ? pos < a.pos : x < a.x;
}
}p[N];
int main()
{
scanf("%d", &n);
p[1] = { -INF,1 }, p[n + 2] = { INF,n + 2 };
for(int i = 2; i <= n + 1; i++)
{
scanf("%d", &p[i].x);
p[i].pos = i;
}
sort(p + 2, p + 2 + n);
build(rt, 1, n + 2);
for(int i = 2; i <= n; i++)
{
splay(p[i].pos, 0);
int ans = tr[tr[rt].s[0]].sz;
printf("%d ", ans);
int L = get_k(i - 1);
int R = get_k(ans + 2);
splay(L, 0); splay(R, L);
tr[tr[R].s[0]].flag ^= 1;
}
printf("%d\n", n);
return 0;
}
四 倍 经 验