[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][ ...
随机推荐
- oracle_多表查询02
多表查询 select * from BONUS; select * from DEPT; select * from EMP; select * from SALGRADE; BONUS表 ENAM ...
- 服务器上office不能正常使用?
(1)确保dll版本和服务器上office版本一致 (2)配置dcom (3)项目配置文件中添加用户模拟语句 <system.web> <identity impersonate=& ...
- JS 控制特殊字符
1.标签上直接替换方法: JS 控制不能输入特殊字符 1 <input type="text"class="domain"onkeyup="th ...
- SpringBoot整合Redis---Jedis版
目录 介绍 开发环境 pom文件引入 创建redis.properties配置文件 创建RedisConfig配置类 创建RedisUtil工具类 使用 效果 介绍 Redis简介 Redis 是完全 ...
- mybatis+oracle 批量插入,若数据库中有则做更新操作
1.只批量插入: insert into WXPAY_ACCOUNT(id ,out_trade_no ,transaction_id)select SEQ_WXPAY_ACCOUNT.nextval ...
- axios 简单二次封装
import axios from 'axios' import { Message } from 'element-ui'; // 设置baseURL //axios.defaults.baseUR ...
- 【Git】三、版本回退&撤消修改&文件删除
提要 //查看git操作日志 $ git log //单行格式查看操作日志 $ git log --pretty=oneline //还原操作到上一次版本,有几个^就上几次 $ git reset - ...
- list列表的使用
Python最常用的数据类型之一,通过列表可以对数据实现最方便的存储.修改等操作 list1 = [1,2,3,4,5,6,7,8,9] #创建列表 z = list([1,2,3,4,5,6,7,8 ...
- Django—ModelForm
简介 Model + Form ==> ModelForm.model和form的结合体,所以有以下功能: 验证 数据库操作 Form回顾 models.py class UserType(mo ...
- 关于Linux连接工具mobaxterm显示中文乱码问题
本人用的是MobaXterm Personal 9.1版本.近期发现连接上服务器,查看日志时,发现中文乱码,无法正常显示.甚是苦恼.百度搜索该工具显示乱码问题,无一人解决.提倡更换连接工具.无意间发现 ...