[Luogu] 排序机械臂
https://www.luogu.org/problemnew/solution/P3165
预处理
我们会发现一个问题:高度是无序的,而splay中要求有序,否则kth不能正确求解。
不需要求高度,只要求位置。
所以,用结构体存入 高度 与 下标,按高度排序,然后就可以把高度丢一边了(一波sao操作)。
记得头尾添加两个节点。。。
建树
正常 nlogn 可能会被卡常,所以,类似于线段树的建树,分此节点与左右儿子节点。
区间第k大
正常kth
区间翻转
首先,需要把所求的节点(即排序前下标为id的节点) splay 到 root 。
那么答案就是root左孩子的节点个数(因为有哨兵节点,所以+1-1抵消),记为s。
然后,取出 [i+1 , s+1] 这段区间,即:
将i节点 splay 到根,s+2节点 splay 到i的右节点。
再将s+2的左孩子打上翻转标记即可。
#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 100010
#define MAX 999999999//最值
using namespace std;
int n,size=,root=;
struct node {
int x,id;
} b[MAXN];
namespace splay {
struct Splay {
int f,s,flag,son[];
int v;
} a[MAXN];
inline void clean(int rt) { //清空节点
a[rt].son[]=a[rt].son[]=a[rt].f=a[rt].s=a[rt].flag=a[rt].v=;
}
inline void pushup(int rt) { //上传
if(!rt)return;
a[rt].s=a[a[rt].son[]].s+a[a[rt].son[]].s+;
}
inline void pushdown(int rt) { //标记下传
if(!rt||!a[rt].flag)return;//记得这句
a[a[rt].son[]].flag^=;
a[a[rt].son[]].flag^=;
a[rt].flag^=;
swap(a[rt].son[],a[rt].son[]);
}
inline void turn(int rt,int k) { //旋转
int x=a[rt].f,y=a[x].f;
a[x].son[k^]=a[rt].son[k];
if(a[rt].son[k])a[a[rt].son[k]].f=x;
a[rt].f=y;
if(y)a[y].son[a[y].son[]==x]=rt;
a[x].f=rt;
a[rt].son[k]=x;
pushup(x);
pushup(rt);
}
void splay(int rt,int ancestry) { //伸展
while(a[rt].f!=ancestry) {
int x=a[rt].f,y=a[x].f;
pushdown(y);
pushdown(x);
pushdown(rt);//每次都要下传
if(y==ancestry)turn(rt,a[x].son[]==rt);
else {
int k=a[y].son[]==x?:;
if(a[x].son[k]==rt) {
turn(rt,k^);
turn(rt,k);
} else {
turn(x,k);
turn(rt,k);
}
}
}
if(ancestry==)root=rt;
}
inline int newnode(int x) { //建立新节点
int rt=size++;
clean(rt);
a[rt].v=x;
a[rt].s=;
return rt;
}
int buildtree(int l,int r) { //建树
if(l>r)return ;
int mid=l+r>>,lson=,rson=;
lson=buildtree(l,mid-);
int rt=newnode(b[mid].x);
rson=buildtree(mid+,r);
a[rt].son[]=lson;
a[rt].son[]=rson;
if(lson)a[lson].f=rt;
if(rson)a[rson].f=rt;
pushup(rt);//一定要有这句!
return rt;
}
int kth(int rt,int k) { //第k大值
if(a[rt].s<k)return ;
while() {
pushdown(rt);//下传
int y=a[rt].son[];
if(k>a[y].s+) {
k-=a[y].s+;
rt=a[rt].son[];
} else if(k<=a[y].s)rt=y;
else return rt;
}
}
inline void reverge(int i) { //区间翻转
splay(b[i].id+,);//记得加1(有哨兵节点)
int s=a[a[root].son[]].s;
printf("%d ",s);
int front=kth(root,i),next=kth(root,s+);
splay(front,);
splay(next,front);
a[a[next].son[]].flag^=;//打上标记
}
}
inline int read() {
int date=,w=;
char c=;
while(c<''||c>'') {
if(c=='-')w=-;
c=getchar();
}
while(c>=''&&c<='') {
date=date*+c-'';
c=getchar();
}
return date*w;
}
bool cmp(const node &x,const node &y) {
if(x.x==y.x)return x.id<y.id;
return x.x<y.x;
}
void init() { //预处理+读入+工作
n=read();
for(int i=; i<=n; i++) {
b[i].x=read();
b[i].id=i;
}
b[].x=-MAX;
b[].id=;
b[n+].x=MAX;
b[n+].id=n+;//两个哨兵节点
sort(b+,b+n+,cmp);
root=splay::buildtree(,n+);
for(int i=; i<=n-; i++)splay::reverge(i);
printf("%d\n",n);//最后一个一定是 n
}
int main() {
init();
return ;
}
[Luogu] 排序机械臂的更多相关文章
- 【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间的物品反序:第二次找到第二低的物品 ...
- Luogu P3165 [CQOI2014]排序机械臂
先讲一下和这题一起四倍经验的题: Luogu P4402 [Cerc2007]robotic sort 机械排序 SP2059 CERC07S - Robotic Sort UVA1402 Robot ...
- 【BZOJ-1552&3506】robotic sort&排序机械臂 Splay
1552: [Cerc2007]robotic sort Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 806 Solved: 329[Submit][ ...
随机推荐
- Django学习(2.2.1版本)
项目技术重难点分析: 模型层:模型是您的数据唯一而且准确的信息来源.它包含您正在储存的数据的重要字段和行为.一般来说,每一个模型都映射一个数据库表. 每各模型都是一个python的类,这些类继承 d ...
- Linux/CentOS 配置Mysql-server过程和遇到错误解决方法
第一步:下载mysql-server 方法1.wget url(你所要下载的链接,可以从mysq官网查找)到当前目录下 方法2.到mysql官网下载包之后通过xftp传到linux 第二步:解压tar ...
- 在Linux上安装和配置CSF(配置服务器安全和防火墙)
CSF是国外一家小公司开发的linux系统免费防火墙,它基于iptables工作,能有效缓解服务器压力,具有自动屏蔽暴力破解密码IP.管理开放端口.免疫轻量DDos和CC等等功能,同时,安装和使用也极 ...
- MyBatis 源码篇-整体架构
MyBatis 的整体架构分为三层, 分别是基础支持层.核心处理层和接口层,如下图所示. 基础支持层 反射模块 该模块对 Java 原生的反射进行了良好的封装,提供了更加简洁易用的 API ,方便上层 ...
- 怎样使用yum安装nginx
yum install -y nginx 以上.
- Outline 科学的上网
outline 官网:https://getoutline.org/zh-CN/home 下载 Outline 管理器 下载 Outline 客户端 配置浏览器代理
- eclipse svn 插件离线安装后connector获取不到的问题解决
最近换了一家公司,写代码的电脑不给外网,所以各种麻烦的问题就来了,这里就说一下eclipse 安装SVN插件的一个小问题,虽说是小问题,但也折腾了我好几个小时,当然也可以不用这个插件,直接安装SVN客 ...
- windows BAT脚本2个服务器间传递文件
1. 脚本功能: 实现2个服务器间文件的传递,例如从A服务器往B服务器上传文件 2. 实现步骤: 2.1 服务器连结,找到指定路径,读取所需要上传的文件,将文件名称复制到一个文件下 (此处考虑可能需要 ...
- JavaScript捕获和冒泡探讨
<div id="div"> <input type="button" value="banana" id="b ...
- 4.caffe资源汇总(更新中)
学习需要更新,网上有一些非常不错博客. 感谢这些博主,他们都很认真. 00.tornadomeet 0.denny的学习专栏 1.xizero00 2.lingerlanlan 3.iamzhangz ...