[BZOJ 1552] 排序机械臂

Splay大法是坠吼滴!

1552: [Cerc2007]robotic sort

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 436  Solved: 186
[Submit][Status][Discuss]

Description

[BZOJ 1552] 排序机械臂

Input

输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000。第二行为N个用空格隔开的正整数,表示N个物品最初排列的编号。

Output

输出共一行,N个用空格隔开的正整数P1,P2,P3…Pn,(1 < = Pi < = N),Pi表示第i次操作前第i小的物品所在的位置。 注意:如果第i次操作前,第i小的物品己经在正确的位置Pi上,我们将区间[Pi,Pi]反转(单个物品)。

Sample Input

6
3 4 5 1 6 2

Sample Output

4 6 4 5 6 6

HINT

Source

还算水的一道区间维护题目, 操作涉及区间翻转所以要用无旋 $Treap$ 或者$Splay$ .

主要思路是每次先建出这棵平衡树, 维护以结点为根的子树的大小, 最小值和最小值所在的子树(左/右/根), 然后每次根据保存的最小值的位置去查找并根据子树大小计算它所在的下标. 然后每次找到之后将其作为区间右端点, 左端点由于是顺序的所以直接从 $1$ 到 $n$ 枚举, 将这个选定的区间翻转即可. 翻转后这个最小值会对后面的计算产生额外影响所以要将已经排好序的结点的值重置为 $\infty$ 并向上更新.

以及题目要求该排序必须做到稳定, 所以我们保存数据时可以使用 $std::pair$, 第一关键字为键值, 第二关键字为该键值初始时的下标.

虚拟结点为了防止干扰答案 (本题中求最小值是针对整棵树, 而不像某维修数列全是指定区间结果虚拟结点一直在待求值的子树外) 键值与最小值均为 $\infty$,

然后就是注意没事多写几个标记下传操作, 标记下传多了顶多让你常数大点, 但下传少了可是会出人命的...

还有Splay的时候判根要判 $prt$ 是否等于传入的第二个参数而不是直接和 $NULL$ 比较(被坑), Splay内部的旋转要么以 $prt$ 为转轴要么以 $prt$ 的 $prt$ 为转轴, 不要脑抽写成以本结点为转轴 (又被坑了我好菜啊)

参考代码如下:

GitHub

 #include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm> #define lch chd[0]
#define rch chd[1]
#define kch chd[k]
#define xch chd[k^1] const int INF=0x7FFFFFFF;
typedef std::pair<int,int> pr; class SplayTree{
private:
struct Node{
pr k;
int s;
pr m;
int mp;
bool rev;
Node* prt;
Node* chd[];
Node(const pr& key){
this->s=;
this->mp=-;
this->k=key;
this->m=key;
this->prt=NULL;
this->lch=NULL;
this->rch=NULL;
this->rev=false;
}
~Node(){
delete this->lch;
delete this->rch;
}
inline void Flip(){
if(this==NULL)
return;
this->rev=!this->rev;
std::swap(this->lch,this->rch);
if(this->mp!=-)
this->mp^=;
}
inline void PushDown(){
if(this!=NULL&&this->rev){
this->lch->Flip();
this->rch->Flip();
this->rev=false;
}
}
inline void Maintain(){
if(this!=NULL){
this->s=this->lch->size()+this->rch->size()+;
this->m=this->k;
this->mp=-;
if(this->lch->min()<this->m){
this->m=this->lch->min();
this->mp=;
}
if(this->rch->min()<this->m){
this->m=this->rch->min();
this->mp=;
}
}
}
inline pr min(){
return this==NULL?std::make_pair(INF,INF):this->m;
}
inline int minp(){
return this==NULL?-:this->mp;
}
inline int size(){
return this==NULL?:this->s;
}
inline pr key(){
return this==NULL?std::make_pair(INF,INF):this->k;
}
}*root;
void Rotate(Node* root,int k){
Node* tmp=root->xch;
root->PushDown();
tmp->PushDown();
tmp->prt=root->prt;
if(root->prt==NULL)
this->root=tmp;
else if(root->prt->lch==root)
root->prt->lch=tmp;
else
root->prt->rch=tmp;
root->xch=tmp->kch;
if(root->xch!=NULL)
root->xch->prt=root;
tmp->kch=root;
root->prt=tmp;
root->Maintain();
tmp->Maintain();
}
void Splay(Node* root,Node* prt=NULL){
while(root->prt!=prt){
int k=root->prt->lch==root;
if(root->prt->prt==prt)
Rotate(root->prt,k);
else{
int d=root->prt->prt->lch==root->prt;
Rotate(k==d?root->prt->prt:root->prt,k);
Rotate(root->prt,d);
}
}
}
Node* Build(const std::vector<pr>& v,int l,int r){
if(l>r)
return NULL;
int mid=(l+r)>>;
Node* tmp=new Node(v[mid]);
tmp->lch=Build(v,l,mid-);
if(tmp->lch!=NULL)
tmp->lch->prt=tmp;
tmp->rch=Build(v,mid+,r);
if(tmp->rch!=NULL)
tmp->rch->prt=tmp;
tmp->Maintain();
return tmp;
}
void PrintTree(Node* root,int deep){
for(int i=;i<deep;i++)
fputc(' ',stderr);
if(root==NULL){
fprintf(stderr, "(==============================)\n");
return;
}
fprintf(stderr, "(root=0x%X,key=%d,min=%d,size=%d,minp=%d)\n", root,root->key(),root->min(),root->size(),root->minp());
PrintTree(root->lch,deep+);
PrintTree(root->rch,deep+);
}
public:
SplayTree(){
this->root=NULL;
}
void Import(const std::vector<pr>& v){
delete this->root;
this->root=new Node(std::make_pair(INF,INF));
this->root->rch=new Node(std::make_pair(INF,INF));
this->root->rch->prt=this->root;
this->root->rch->lch=Build(v,,v.size()-);
this->root->rch->lch->prt=this->root->rch;
this->root->rch->Maintain();
this->root->Maintain();
}
void Reverse(int l,int r){
this->Splay(this->Kth(l-));
this->Splay(this->Kth(r+),this->root);
this->root->rch->lch->Flip();
}
Node* Kth(int pos){
pos++;
Node* root=this->root;
while(root!=NULL){
root->PushDown();
int k=root->lch->size()+;
if(pos<k)
root=root->lch;
else if(pos==k)
return root;
else{
pos-=k;
root=root->rch;
}
}
return NULL;
}
void Modify(int pos,pr d){
Node* tmp=this->Kth(pos);
tmp->k=d;
while(tmp!=NULL){
tmp->Maintain();
tmp=tmp->prt;
}
}
int MinPos(){
int ans=;
Node* root=this->root;
while(root->minp()!=-){
root->PushDown();
if(root->minp()){
ans+=root->lch->size()+;
root=root->rch;
}
else
root=root->lch;
}
ans+=root->lch->size()+;
return ans-;
}
void Print(){
this->PrintTree(this->root,);
}
}; int main(){
int n,tmp;
freopen("roboticsort.in","r",stdin);
freopen("roboticsort.out","w",stdout);
SplayTree* t=new SplayTree();
std::vector<pr> v;
scanf("%d",&n);
while(n!=){
v.clear();
for(int i=;i<n;i++){
scanf("%d",&tmp);
v.push_back(std::make_pair(tmp,i));
}
t->Import(v);
for(int i=;i<=n;i++){
int p=t->MinPos();
printf("%d ",p);
t->Reverse(i,p);
t->Modify(i,std::make_pair(INF,i));
}
putchar('\n');
scanf("%d",&n);
}
return ;
}

Backup

[BZOJ 1552] 排序机械臂

上一篇:[BZOJ3506] [Cqoi2014] 排序机械臂 (splay)


下一篇:【Python】 发邮件用 smtplib & email