[BZOJ 1552] 排序机械臂
Splay大法是坠吼滴!
1552: [Cerc2007]robotic sort
Time Limit: 5 Sec Memory Limit: 64 MB
Submit: 436 Solved: 186
[Submit][Status][Discuss]Description
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 2Sample Output
4 6 4 5 6 6HINT
Source
还算水的一道区间维护题目, 操作涉及区间翻转所以要用无旋 $Treap$ 或者$Splay$ .
主要思路是每次先建出这棵平衡树, 维护以结点为根的子树的大小, 最小值和最小值所在的子树(左/右/根), 然后每次根据保存的最小值的位置去查找并根据子树大小计算它所在的下标. 然后每次找到之后将其作为区间右端点, 左端点由于是顺序的所以直接从 $1$ 到 $n$ 枚举, 将这个选定的区间翻转即可. 翻转后这个最小值会对后面的计算产生额外影响所以要将已经排好序的结点的值重置为 $\infty$ 并向上更新.
以及题目要求该排序必须做到稳定, 所以我们保存数据时可以使用 $std::pair$, 第一关键字为键值, 第二关键字为该键值初始时的下标.
虚拟结点为了防止干扰答案 (本题中求最小值是针对整棵树, 而不像某维修数列全是指定区间结果虚拟结点一直在待求值的子树外) 键值与最小值均为 $\infty$,
然后就是注意没事多写几个标记下传操作, 标记下传多了顶多让你常数大点, 但下传少了可是会出人命的...
还有Splay的时候判根要判 $prt$ 是否等于传入的第二个参数而不是直接和 $NULL$ 比较(被坑), Splay内部的旋转要么以 $prt$ 为转轴要么以 $prt$ 的 $prt$ 为转轴, 不要脑抽写成以本结点为转轴 (又被坑了我好菜啊)
参考代码如下:
#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】排序机械臂(Splay)
[BZOJ3506]排序机械臂(Splay) 题面 神TMBZOJ没有题面,感谢SYC的题面 洛谷的题面也不错 题解 对于每次旋转的物体 显然可以预处理出来 现在只要模拟旋转操作就行了 至于在哪里放标 ...
- P3165 [CQOI2014]排序机械臂
题目描述 为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂.它遵循一个简单的排序规则,第一次操作找到高度最低的物品的位置 P1P_1P1 ,并把左起第一个物品至 P1P_1P1 ...
- 【BZOJ3506】[CQOI2014] 排序机械臂(Splay)
点此看题面 大致题意: 给你\(n\)个数.第一次找到最小值所在位置\(P_1\),翻转\([1,P_1]\),第二次找到剩余数中最小值所在位置\(P_2\),翻转\([2,P_2]\),以此类推.求 ...
- LibreOJ2241 - 「CQOI2014」排序机械臂
Portal Description 给出一个\(n(n\leq10^5)\)个数的序列\(\{a_n\}\),对该序列进行\(n\)次操作.若在第\(i\)次操作前第\(i\)小的数在\(p_i\) ...
- 刷题总结:排序机械臂(石室中学oj)(splay)
题目: 题目描述 为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂.它遵循一个简单的排序规则,第一次操作找到最低的物品位置 P1,并把从左起第 1 个至第 P1 个之间的物品反序 ...
- [bzoj1552\bzoj2506][Cqoi2014]robotic sort 排序机械臂_非旋转Treap
robotic sort 排序机械臂 bzoj-1552 bzoj-2506 Cqoi-2014 题目大意:给定一个序列,让你从1到n,每次将[1,p[i]]这段区间反转,p[i]表示整个物品权值第i ...
- 洛谷P3165 [CQOI2014]排序机械臂
题目描述 为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂.它遵循一个简单的排序规则,第一次操作找到摄低的物品的位置P1,并把左起第一个至P1间的物品反序:第二次找到第二低的物品 ...
- 【BZOJ】【1552】【Cerc2007】robotic sort / 【3506】【CQOI2014】排序机械臂
Splay 离散化+Splay维护序列…… 好吧主要说一下我做这道题遇到的几个错误点: 1.离散化 2.由于找到的这个数的位置一定是大于等于 i 的,所以其实在把它splay到根以后,i 结点只能sp ...
- BZOJ3506/1502 [CQOI2014]排序机械臂
传送门 依然是一道splay的区间操作,需要注意的是要把下标离散化后来表示splay的节点,我不知道怎么搞所以索性弄了个$ValuetoNode$,看样子没什么问题, 感觉他那个传下标的方法太暴力了. ...
随机推荐
- JDK源码--ArrayList浅析
先上别人的源码分析http://www.cnblogs.com/roucheng/p/jdkfenxi.html 这个链接也不错:http://www.jianshu.com/p/8d14b55fa1 ...
- php中常量 const属性,静态属性,静态的函数方法
<?php//php中的常量define('MYNUM', 2000);echo MYNUM.'<br>';if(!defined('MYNUM')){ define('MYNUM' ...
- 【css】清除浮动的几种方式
[css]清除浮动的几种方式 因为浮动框不在普通的文档流中,所以它不占据空间.如下面的代码: .news { background-color:gray; border:1px solid bla ...
- [转]wxParse-微信小程序富文本解析组件
本文转自:https://github.com/icindy/wxParse 基本使用方法 Copy文件夹wxParse - wxParse/ -wxParse.js(必须存在) -html2json ...
- 为什么会出现__pycache__文件夹?
为什么会出现__pycache__文件夹? python解释器会将 *.py 脚本文件进行编译,并将编译结果保存到__pycache__目录中. 下次再执行工程时,若解释器发现这个 *.py 脚本没有 ...
- 撩课-Java每天5道面试题第21天
136.请解释Spring Bean的生命周期? 首先说一下Servlet的生命周期: 实例化, 初始init, 接收请求service, 销毁destroy: Spring上下文中的Bean生命周期 ...
- 【SSH网上商城项目实战28】使用Ajax技术局部更新商品数量和总价
转自: https://blog.csdn.net/eson_15/article/details/51487323 昨天把项目部署了一下,玩了玩,今天完善了一下购物车中修改商品数量就能局部 ...
- 如何迎接新的 .NET 时代
看完.NET 基金会. Roslyn 编译器 ,应该已经能慢慢了解,现在所谓的“.NET 开源”.“.NET Open Source”并不是完全把现有的 .NET Framework 整个打开(虽然这 ...
- Sspring bean被初始化加载2次
Sspring bean被初始化加载2次 spring框架的web项目时,启动的时候发现某个bean被加载了两次,比如使用SchedulingConfigurer或者使用@PostConstruct的 ...
- HTML颜色的三种写法
颜色的三种写法: 1.16进制代码 #000000 2.英文字母 red 3.rgba rgba(0-255,0,0,0-1) 例如: <b ...