[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][ ...
随机推荐
- Pangu and Stones(HihoCoder-1636)(17北京OL)【区间DP】
题意:有n堆石头,盘古每次可以选择连续的x堆合并,所需时间为x堆石头的数量之和,x∈[l,r],现在要求,能否将石头合并成一堆,如果能,最短时间是多少. 思路:(参考了ACM算法日常)DP[i][j] ...
- unittest参数化(paramunittest)
前言 paramunittest是unittest实现参数化的一个专门的模块,可以传入多组参数,自动生成多个用例前面讲数据驱动的时候,用ddt可以解决多组数据传入,自动生成多个测试用例.本篇继续介绍另 ...
- python 画图像训练结果的loss图
得到每个epoch的loss和predict精度后,就可以愉快地画图直观地看出训练结果和收敛性了. # coding:utf-8 import matplotlib.pyplot as plt dat ...
- C# Math.Round()的银行家算法
可能很多人都跟我一样,都只知道Math.Round()是C#中用来做四舍五入,保留指定小数位的 但实际上它并不是真正的四舍五入,而是银行家算法的四舍六入五取偶 事实上这也是IEEE的规范,因此所有符合 ...
- SQLSERVER 20018 R2 T-SQL 创建linkServer
1. SQLSERVER LINK SQLSERVER EXEC sp_addlinkedserver @server = 'LINKTEST',@srvproduct = '',@provider ...
- ASP .NET依赖注入理解
ASP .NET依赖注入理解[转]: https://www.cnblogs.com/wzk153/p/10892444.html
- javaIO——StringReader & StringWriter
上一篇概述篇说过,一个IO对象是指一个可以被关闭的数据源或者目标,那么StringReader和StringWriter就是一个字符串源和字符串目标. 1. StringtReader: 文档说:St ...
- Saladict 沙拉查词
Saladict 沙拉查词 鼠标中键呼出 整合了有道翻译.百度翻译.必应翻译.腾讯翻译君. Google 翻译和彩云小译等,自动发音,可配置词典. 说明文档:https://github.com/cr ...
- ASE19团队项目alpha阶段model组 scrum10 记录
本次会议于11月14日,19时整在微软北京西二号楼sky garden召开,持续5分钟. 与会人员:Jiyan He, Kun Yan, Lei Chai, Linfeng Qi, Xueqing W ...
- Spring Cloud(十)高可用的分布式配置中心 Spring Cloud Config 中使用 Refresh
上一篇文章讲了SpringCloudConfig 集成Git仓库,配和 Eureka 注册中心一起使用,但是我们会发现,修改了Git仓库的配置后,需要重启服务,才可以得到最新的配置,这一篇我们尝试使用 ...