题目描述

输入

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

输出

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

样例输入

6
3 4 5 1 6 2

样例输出

4 6 4 5 6 6
 
非旋转treap练习题。题目要求每次找到第i小的Pi并将i~Pi翻转,因为在第i次操作时,前i小的数在最前面不会被翻转,之后也不会被用到。那么我们可以对序列建非旋转treap每次找到最小的,然后删除掉它,再将它原位置之前的部分翻转即可。但发现不能只维护子树最小值,因为有相同值时要选编号小的,也不能有多个最小值优先遍历左子树,因为原先编号小的翻转后可能成了右子树。所以我们先将原序列排个序,按排序后的顺序作为他们新的权值,再按原顺序插入treap,这样每个点的权值就是独一无二的了,直接记录最小值每次查找即可。不要忘记查找时也要下传翻转标记。

#include<set>
#include<map>
#include<stack>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int n;
int cnt;
int root;
int x,y,z;
int v[100010];
int s[100010];
int r[100010];
int mn[100010];
int ls[100010];
int rs[100010];
int size[100010];
struct miku
{
int val;
int num;
int rak;
}a[100010];
bool cmp1(miku a,miku b)
{
if(a.val!=b.val)
{
return a.val<b.val;
}
return a.num<b.num;
}
bool cmp2(miku a,miku b)
{
return a.num<b.num;
}
int build(int val)
{
int rt=++cnt;
r[rt]=rand();
v[rt]=val;
mn[rt]=val;
size[rt]=1;
return rt;
}
void rotate(int rt)
{
swap(ls[rt],rs[rt]);
s[rt]^=1;
}
void pushup(int rt)
{
size[rt]=size[ls[rt]]+size[rs[rt]]+1;
mn[rt]=v[rt];
if(ls[rt])
{
mn[rt]=min(mn[rt],mn[ls[rt]]);
}
if(rs[rt])
{
mn[rt]=min(mn[rt],mn[rs[rt]]);
}
}
void pushdown(int rt)
{
if(s[rt])
{
if(ls[rt])
{
rotate(ls[rt]);
}
if(rs[rt])
{
rotate(rs[rt]);
}
s[rt]^=1;
}
}
int merge(int x,int y)
{
if(!x||!y)
{
return x+y;
}
pushdown(x);
pushdown(y);
if(r[x]<r[y])
{
rs[x]=merge(rs[x],y);
pushup(x);
return x;
}
else
{
ls[y]=merge(x,ls[y]);
pushup(y);
return y;
}
}
void split(int rt,int k,int &x,int &y)
{
if(!rt)
{
x=y=0;
return ;
}
pushdown(rt);
if(size[ls[rt]]<k)
{
x=rt;
split(rs[rt],k-size[ls[rt]]-1,rs[x],y);
}
else
{
y=rt;
split(ls[rt],k,x,ls[y]);
}
pushup(rt);
}
int rank(int rt)
{
pushdown(rt);
int res=v[rt];
if(ls[rt])
{
res=min(res,mn[ls[rt]]);
}
if(rs[rt])
{
res=min(res,mn[rs[rt]]);
}
if(res==mn[ls[rt]])
{
return rank(ls[rt]);
}
else if(res==v[rt])
{
return size[ls[rt]]+1;
}
else
{
return size[ls[rt]]+1+rank(rs[rt]);
}
}
int main()
{
srand(20020419);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].val);
a[i].num=i;
}
sort(a+1,a+1+n,cmp1);
for(int i=1;i<=n;i++)
{
a[i].rak=i;
}
sort(a+1,a+1+n,cmp2);
for(int i=1;i<=n;i++)
{
root=merge(root,build(a[i].rak));
}
for(int i=1;i<=n;i++)
{
int ans=rank(root);
printf("%d",i-1+ans);
if(i!=n)
{
printf(" ");
}
split(root,ans-1,x,y);
split(y,1,y,z);
rotate(x);
root=merge(x,z);
}
}

BZOJ1552[Cerc2007]robotic sort&BZOJ3506[Cqoi2014]排序机械臂——非旋转treap的更多相关文章

  1. [bzoj1552][Cerc2007]robotic sort&&[bzoj3506][Cqoi2014]排序机械臂

    非常垃圾的一道平衡树,结果被日了一天.很难受嗷嗷嗷 首先不得不说网上的题解让我这个本来就不熟悉平衡树的彩笔很难受——并不好理解. 还好Sinogi大佬非常的神,一眼就切掉了,而且用更加美妙的解法. 题 ...

  2. bzoj3506 [Cqoi2014]排序机械臂

    bzoj3506 此题是一道比较简单的spaly题目. 用splay维护序列,将每个点排到对应的位置之后删除,这样比较容易区间翻转. 我的指针写法在洛谷上AC了,但在bzoj上RE. #include ...

  3. [BZOJ3506] [Cqoi2014] 排序机械臂 (splay)

    Description 同OJ1552 Input Output Sample Input Sample Output HINT Source Solution Q:哎不是同一道题吗为什么分两篇博客来 ...

  4. 【BZOJ3506】[CQOI2014] 排序机械臂(Splay)

    点此看题面 大致题意: 给你\(n\)个数.第一次找到最小值所在位置\(P_1\),翻转\([1,P_1]\),第二次找到剩余数中最小值所在位置\(P_2\),翻转\([2,P_2]\),以此类推.求 ...

  5. [BZOJ1552][Cerc2007]robotic sort

    [BZOJ1552][Cerc2007]robotic sort 试题描述 输入 输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000.第二行为N个用空格隔开的正整数 ...

  6. 【BZOJ3506】排序机械臂(Splay)

    [BZOJ3506]排序机械臂(Splay) 题面 神TMBZOJ没有题面,感谢SYC的题面 洛谷的题面也不错 题解 对于每次旋转的物体 显然可以预处理出来 现在只要模拟旋转操作就行了 至于在哪里放标 ...

  7. Luogu P3165 [CQOI2014]排序机械臂

    先讲一下和这题一起四倍经验的题: Luogu P4402 [Cerc2007]robotic sort 机械排序 SP2059 CERC07S - Robotic Sort UVA1402 Robot ...

  8. P3165 [CQOI2014]排序机械臂

    题目描述 为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂.它遵循一个简单的排序规则,第一次操作找到高度最低的物品的位置 P1P_1P1​ ,并把左起第一个物品至 P1P_1P1 ...

  9. 洛谷P3165 [CQOI2014]排序机械臂

    题目描述 为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂.它遵循一个简单的排序规则,第一次操作找到摄低的物品的位置P1,并把左起第一个至P1间的物品反序:第二次找到第二低的物品 ...

随机推荐

  1. MySQL(十三)事务处理和字符集

    一.事务处理 事务处理(transaction processing):是一种机制,用来维护数据库的完整性,管理必须成批执行的MySQL操作,以保证数据库不包含不完整的操作结果. 这样可以保证一组操作 ...

  2. 软概(lesson 1):Javaweb实现用户登录界面

    一.问题描述 二.网站系统开发所需要的技术 网站界面开发:html 后台所需要的技术:java基本内容,数据库语句,连接数据库实现增删改查 本题所用技术:数据库链接以及增加功能,基本html语句 技术 ...

  3. Omi框架学习之旅 - 插件机制之omi-finger 及原理说明

    以前那篇我写的alloyfinger源码解读那篇帖子,就说过这是一个很好用的手势库,hammer能做的,他都能做到, 而且源码只有350来行代码,很容易看懂. 那么怎么把这么好的库作为omi库的一个插 ...

  4. Oracle 在函数或存储过程中执行一条插入语句并返回主键ID值

    有时,我们需要往一张表插入一条记录,同时返回主键ID值. 假定主键ID的值都是通过对应表的SEQUENCE来获得,然后进行ID赋值 这里有几种情况需要注意: 1)如果建表语句含有主键ID的触发器,通过 ...

  5. webstorm破解汉化

    一.下载webstorm软件和汉化包 webstorm安装包下载链接 : 链接: https://pan.baidu.com/s/1VmOPNVL2GRgAb_0tAJhy8A 密码: am7e 汉化 ...

  6. Winio驱动在64位windows下无法使用的解决方法

    C#在使用WinIo的驱动开发类似按键精灵一类工具的时候,需要对相关的驱动进行注册才能正常启动,找了下资料,资料来自: http://jingyan.baidu.com/article/642c9d3 ...

  7. 【转】浅谈JavaScript中forEach与each

    forEach是ES5中操作数组的一种方法,主要功能是遍历数组,例如: var arr = [1,2,3,4]; arr.forEach(alert); 等价于: var arr = [1, 2, 3 ...

  8. VS2017一步一步断点调试解决Dapper语句出现的Bug

    最近再做一个项目,出现一个小bug,bug虽小,但是却要命啊.下面我show下我解决问题的方法. View层代码: @model List<mhq.Blog.Model.Blog> < ...

  9. Flutter - 自动生成Android & iOS图标

    对于要发布的app来说,做图标是一个麻烦的事,你需要知道N个图标的分辨率,然后用PhotoShop一个个修改导出. PS好图标之后,按照各自的位置放进去. ********************** ...

  10. Jmeter(三十三)_JsonPath表达式提取响应

    我们在用jmeter做接口测试的时候,有的时候会遇到一些复杂的json响应.比如多层list嵌套时的取值 一个简单的例子: $..Name:列出所有省份 $..Province[0].Name 提取P ...