Luogu P3165 [CQOI2014]排序机械臂
先讲一下和这题一起四倍经验的题:
这题作为一道十分经典的平衡树维护序列的问题,自然是值得一做的了。
写完翻了下题解发现都是写Splay的dalao,少有的暴力FHQ_Treap党还是用指针实现的。
所以这里略微讲解下数组实现的FHQ_Treap好了,感觉写起来比Splay舒服些。
首先我们要抽象化一下题意:给你\(n\)个数,第\(i\)次操作在\([i,n]\)中找到最小值的位置\(p_i\),并翻转\([i,p_i]\)。最后输出所有\(p_i\)的值。
然后我们考虑转化问题(因为貌似FHQ_Treap不能同时支持基于权值的split
和基于排名的分裂)。
所以离散化是必须的,尤其注意这里不能直接对数组排序(因为会有权值相等的点)。
然后我们记一下每个值原来的位置,再考虑对一个基本序列(即初始时为\(1,2,3,\dots,n\))进行翻转。
手动推导一下我们发现其实就是先找出每次操作位置的排名,然后再基本序列上不停翻转区间即可。
由于FHQ_Treap树高期望\(\log\)的特性,所以我们查询排名的时候可以直接暴力从一个点跳到根然后反着算回来。
最后提一下那种以权值为保证堆性质的值的做法是错误的!这样会导致树高不平衡,一旦遇到单调的数据就卡到\(O(n^2)\)了。
CODE
#include<cstdio>
#include<cctype>
#include<algorithm>
#define RI register int
#define CI const int&
#define Tp template <typename T>
using namespace std;
const int N=100005;
struct data
{
int val,id;
inline friend bool operator <(const data& A,const data& B)
{
return A.val<B.val||(A.val==B.val&&A.id<B.id);
}
}a[N]; int n,rk;
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
#define pc(ch) (Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch))
char Fin[S],Fout[S],*A,*B; int Ftop,pt[15];
public:
Tp inline void read(T& x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
Tp inline void write(T x)
{
if (!x) return (void)(pc('0'),pc(' ')); RI ptop=0;
while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc(' ');
}
inline void Fend(void)
{
fwrite(Fout,1,Ftop,stdout);
}
#undef tc
#undef pc
}F;
class FHQ_Treap
{
private:
struct treap
{
int ch[2],size,dat,fa; bool rev;
inline treap(CI Dat=0,CI Size=0)
{
ch[0]=ch[1]=rev=fa=0; dat=Dat; size=Size;
}
}node[N]; int tot,rt,seed,stack[N],top;
#define lc(x) node[x].ch[0]
#define rc(x) node[x].ch[1]
#define fa(x) node[x].fa
inline int rand(void)
{
return seed=(int)seed*482711LL%2147483647;
}
inline void swap(int& x,int& y)
{
int t=x; x=y; y=t;
}
inline void rever(CI x)
{
swap(lc(x),rc(x)); node[x].rev^=1;
}
inline void pushup(CI x)
{
node[x].size=node[lc(x)].size+node[rc(x)].size+1; fa(lc(x))=fa(rc(x))=x;
}
inline void pushdown(CI x)
{
if (node[x].rev) rever(lc(x)),rever(rc(x)),node[x].rev=0;
}
inline void merge(int& now,int x,int y)
{
if (!x||!y) return (void)(now=x|y); if (node[x].dat>node[y].dat)
pushdown(x),now=x,merge(rc(now),rc(x),y),pushup(x); else
pushdown(y),now=y,merge(lc(now),x,lc(y)),pushup(y);
}
inline void split(int now,int& x,int& y,int rk)
{
if (!now) return (void)(x=y=0); pushdown(now); if (node[lc(now)].size<rk)
x=now,split(rc(now),rc(x),y,rk-node[lc(now)].size-1); else
y=now,split(lc(now),x,lc(y),rk); pushup(now);
}
public:
FHQ_Treap() { seed=233; }
inline void insert(CI val)
{
node[++tot]=treap(rand(),1); merge(rt,rt,tot);
}
inline void reverse(RI l,RI r)
{
int x,y,z; split(rt,x,y,l-1); split(y,y,z,r-l+1);
rever(y); merge(y,y,z); merge(rt,x,y);
}
inline int get_rk(int now)
{
stack[top=1]=now; for (int t=now;fa(t);t=fa(t)) stack[++top]=fa(t);
while (top) pushdown(stack[top--]); int ret=node[lc(now)].size;
for (;now;now=fa(now)) if (now==rc(fa(now))) ret+=node[lc(fa(now))].size+1;
return ret+1;
}
#undef lc
#undef rc
}T;
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i; for (F.read(n),i=1;i<=n;++i) F.read(a[i].val),a[i].id=i;
for (sort(a+1,a+n+1),i=1;i<=n;++i) T.insert(i); for (i=1;i<=n;++i)
rk=T.get_rk(a[i].id),F.write(rk),T.reverse(i,rk); return F.Fend(),0;
}
Luogu P3165 [CQOI2014]排序机械臂的更多相关文章
- P3165 [CQOI2014]排序机械臂
题目描述 为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂.它遵循一个简单的排序规则,第一次操作找到高度最低的物品的位置 P1P_1P1 ,并把左起第一个物品至 P1P_1P1 ...
- 洛谷P3165 [CQOI2014]排序机械臂
题目描述 为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂.它遵循一个简单的排序规则,第一次操作找到摄低的物品的位置P1,并把左起第一个至P1间的物品反序:第二次找到第二低的物品 ...
- [UVA1402]Robotic Sort;[SP2059]CERC07S - Robotic Sort([洛谷P3165][CQOI2014]排序机械臂;[洛谷P4402][Cerc2007]robotic sort 机械排序)
题目大意:一串数字,使用如下方式排序: 先找到最小的数的位置$P_1$,将区间$[1,P_1]$反转,再找到第二小的数的位置$P_2$,将区间$[2,P_2]$反转,知道排序完成.输出每次操作的$P_ ...
- 洛谷P3165 [CQOI2014]排序机械臂 Splay维护区间最小值
可以将高度定义为小数,这样就完美的解决了优先级的问题. Code: #include<cstdio> #include<algorithm> #include<cstri ...
- 【BZOJ3506】[CQOI2014] 排序机械臂(Splay)
点此看题面 大致题意: 给你\(n\)个数.第一次找到最小值所在位置\(P_1\),翻转\([1,P_1]\),第二次找到剩余数中最小值所在位置\(P_2\),翻转\([2,P_2]\),以此类推.求 ...
- 【洛谷 P3165】 [CQOI2014]排序机械臂 (Splay)
题目链接 debug了\(N\)天没debug出来,原来是找后继的时候没有pushdown... 众所周知,,Splay中每个编号对应的节点的值是永远不会变的,因为所有旋转.翻转操作改变的都是父节点和 ...
- BZOJ1552[Cerc2007]robotic sort&BZOJ3506[Cqoi2014]排序机械臂——非旋转treap
题目描述 输入 输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000. 第二行为N个用空格隔开的正整数,表示N个物品最初排列的编号. 输出 输出共一行,N个用空格隔开 ...
- bzoj3506 [Cqoi2014]排序机械臂
bzoj3506 此题是一道比较简单的spaly题目. 用splay维护序列,将每个点排到对应的位置之后删除,这样比较容易区间翻转. 我的指针写法在洛谷上AC了,但在bzoj上RE. #include ...
- BZOJ3506/1502 [CQOI2014]排序机械臂
传送门 依然是一道splay的区间操作,需要注意的是要把下标离散化后来表示splay的节点,我不知道怎么搞所以索性弄了个$ValuetoNode$,看样子没什么问题, 感觉他那个传下标的方法太暴力了. ...
随机推荐
- C# SharpMap的简单使用
本文是利用ShapMap实现GIS的简单应用的小例子,以供学习分享使用.关于SharpMap的说明,网上大多是以ShapeFile为例进行简单的说明,就连官网上的例子也不多.本文是自己参考了源代码进行 ...
- 深入理解Java虚拟机02--Java内存区域与内存溢出异常
一.概述 我们在进行 Java 开发的时候,很少关心 Java 的内存分配等等,因为这些活都让 JVM 给我们做了.不仅自动给我们分配内存,还有自动的回收无需再占用的内存空间,以腾出内存供其他人使用. ...
- 章节一、1-Selenium简介
一.Selenium WebDriver介绍 1.跨平台,用web浏览器做自动化的工具. 2.可以在浏览器上运行的一个框架,用来进行界面的自动化. 3.支持多种计算机语言. 4.可以模拟真实的用户去操 ...
- c++屏蔽Win10系统快捷键
很久之前实现的功能,也是参考其他人的实现,时间太久,具体参考哪里已经记不得了. 这里不仅能屏蔽一般的快捷键,还可以屏蔽ctrl+atl+del. ; HHOOK keyHook = NULL; HHO ...
- JAVA设计模式——代理(静态代理)
定义 为其它的对象提供一种代理,以控制这个对象的访问 使用场景 当不想直接访问某个对象的时候,就可以通过代理 1.不想买午餐,同事帮忙带 2.买车不用去厂里,去4s店 3.去代理点买火车票,不用去车站 ...
- JHipster生成微服务架构的应用栈(二)- 认证微服务示例
本系列文章演示如何用JHipster生成一个微服务架构风格的应用栈. 环境需求:安装好JHipster开发环境的CentOS 7.4(参考这里) 应用栈名称:appstack 认证微服务: uaa 业 ...
- mssql sql语句过滤百分号的方法分享
转自:http://www.maomao365.com/?p=6743 摘要: 下文讲述sql脚本中过滤百分号的方法: 实验环境:sql server 2008 R2 百分号:在sql脚本编写中“百 ...
- 排序算法之希尔排序的思想以及Java实现
1 基本思想 shell排序又称之为缩小增量排序,基本思想是,先将待排序序列分割成若干个特殊的子表,分别进行插入排序,当整个表中元素"基本有序"时,再对全体记录进行一次直接插入排序 ...
- C# → 数据库
Database: public static class dbconnection{ static string cons = "data source = (local) ;initia ...
- js开发打印证书功能
最近突然被加了要打印证书的功能的需求.其实打印功能很简单,直接调用window.print()就可以打印,只是这是最基本的打印,会打印当前页面的所有元素,而我们要的是局部打印,实现方法: 1.设置好开 ...