题目链接

题意:
给你一个长度为nnn的序列,现在有一种对序列排序的方法:假设当前最小的前iii个已经找到了,我们找到i+1i+1i+1到nnn里面最早出现的最小值,设其出现位置为jjj,我们将区间[i+1,j][i+1,j][i+1,j]翻转来排序。输出每次翻转前要找的最小值的位置。
n<=1e5n<=1e5n<=1e5

题解:
首先先吐槽一下,最近可能我实在是太蠢了,这个题硬是写了一天半。网上题解看了不少,都没看懂,感觉好像他们建的平衡树的下标含义和我似乎都不一样。于是最后还是自己yy了一种做法。

这种区间翻转的题,我们还是类似文艺平衡树的方法去用splay维护,为了提取区间方便,我们还是在头尾各加一个节点。我这里splay维护的顺序就是序列的位置顺序,也就是最初中序遍历splay就能得到原序列,只不过我没有在splay的节点上记录数值。

我将每个位置的数值和下标排序,得到这个位置应该是第几次被翻转,记录到了rkrkrk数组中。对于第iii次,我们找到翻转要提取区间,提取区间的前驱是rk[i−1]rk[i-1]rk[i−1],后继是rk[i]rk[i]rk[i]的后继,将rk[i−1]rk[i-1]rk[i−1]转到根,再将那个后继转到根的右儿子,这样区间就被提取到后继的左子树了,就是经典的splay提取区间操作。然后对提取的区间打上翻转标记。每次输出的答案就是将rk[i]rk[i]rk[i]转到根后左子树的大小,本来应该要加一,但是我们左端加了一个点,所以就不用加一了。splay维护的唯一量就是所在子树的size。

特别说一下区间翻转标记的pushdown问题。这里感觉对pushdown有了一些新的理解,但是不保证的对的。感觉网上始终没人说splay的区间标记什么时候应该pushdown,于是我们能见到各自版本的,有的只有在逐层向下查找时pushdown,除了逐层向下时一定要pushdown之外,有的只在splay里pushdown,有的只在rotate里面pushdown,有的既在splay里pushdown又在rotate里pushdown。我这里的写法是在逐层向下查找时pushdown和在splay里pushdown,顺序都是先根节点后子节点。我的理解是,只要需要用到左右儿子信息的时候,就要先pushdown,只要能满足这个,就可以了。而可以不在rotate里面写是因为splay里面已经先对要rotate操作的节点进行了一些条件判断,而在这些判断之前做完pushdown,就可以不在rotate里面pushdown了。

另外这是我第一次把splay写到一个结构体了,虽然这里不写到结构体里应该也没什么区别。

不知道是不是和网上很多题解不太一样的做法,希望能给大家提供一种新思路。

代码:

#include <bits/stdc++.h>
using namespace std;int n,a[100010],root,rk[100010];
struct node
{int sz,c[2],rev,f;
}tr[400010];
struct qwq
{int id,v;
}b[101000];
int cmp(qwq x,qwq y)
{if(x.v==y.v)return x.id<y.id;return x.v<y.v;
}
inline void pushup(int rt)
{tr[rt].sz=tr[tr[rt].c[0]].sz+tr[tr[rt].c[1]].sz+1;
}
inline void build(int rt,int l,int r)
{int mid=(l+r)>>1;if(rt){if(mid<rt)tr[rt].c[0]=mid;elsetr[rt].c[1]=mid;}tr[mid].f=rt;tr[mid].sz=1;if(l!=r){if(l<mid)build(mid,l,mid-1);if(mid+1<=r)build(mid,mid+1,r);}pushup(mid);
}
inline void pushdown(int rt)
{if(tr[rt].rev){if(tr[rt].c[0])tr[tr[rt].c[0]].rev^=1;if(tr[rt].c[1])tr[tr[rt].c[1]].rev^=1;swap(tr[rt].c[0],tr[rt].c[1]);tr[rt].rev=0;}
}
inline void rotate(int x)
{   int y=tr[x].f,z=tr[y].f,k=tr[y].c[1]==x,w=tr[x].c[!k];if(y!=root)tr[z].c[tr[z].c[1]==y]=x;tr[x].c[!k]=y;tr[y].c[k]=w;if(w)tr[w].f=y;tr[y].f=x;tr[x].f=z; pushup(y);pushup(x);
}
inline void splay(int x,int rt)
{while(tr[x].f!=rt){int y=tr[x].f,z=tr[y].f; pushdown(z);pushdown(y);                        pushdown(x);if(tr[y].f!=rt){if(tr[z].c[0]==y ^ tr[y].c[0]==x)rotate(x);elserotate(y);}rotate(x);if(rt==0)root=x;}
}
inline int find()
{int x=root;pushdown(root);x=tr[root].c[1];while(x){pushdown(x);if(tr[x].c[0])x=tr[x].c[0];elsereturn x;}
}
int main()
{scanf("%d",&n);for(int i=2;i<=n+1;++i)scanf("%d",&a[i]);for(int i=2;i<=n+1;++i){b[i-1].id=i;b[i-1].v=a[i];}sort(b+1,b+n+1,cmp);for(int i=1;i<=n;++i)rk[i+1]=b[i].id;rk[1]=1;rk[n+2]=n+2;a[1]=1e9;a[n+2]=1e9;a[0]=1e9;build(0,1,n+2);root=(1+n+2)>>1;for(int i=2;i<=n+1;++i){splay(rk[i],0);int x=tr[tr[rk[i]].c[0]].sz;int yy=find();printf("%d ",x);splay(rk[i-1],0);splay(yy,rk[i-1]);int y=tr[root].c[1],z=tr[y].c[0];tr[z].rev^=1;}return 0;
}

洛谷3165 CQOI2014 排序机械臂 splay相关推荐

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

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

  2. 【splay】BZOJ 1152 3506:[cqoi2014]排序机械臂

    BZOJ 1152 && 3506:[cqoi2014]排序机械臂 Description Input 输入共两行,第一行为一个整数N,N表示物品的个数,第二行为N个用空格隔开的正整数 ...

  3. bzoj 1552: [Cerc2007]robotic sort bzoj 3506: [Cqoi2014]排序机械臂(splay区间翻转)

    1552: [Cerc2007]robotic sort Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 1206  Solved: 460 [Submi ...

  4. P3165 [CQOI2014]排序机械臂

    传送门 就是说要维护一个数据结构资瓷区间反转和查询第\(K\)大,那么splay吧 我们可以把原数组按高度为第一关键字,下标为第二关键字排序,然后直接建出splay 这样的话每次第\(K\)大直接查询 ...

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

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

  6. 【bzoj3506】【CQOI2014】排序机械臂

    Description 有n个物品,每个物品有它的高度a[i],现在我们要采用一种神奇的方法把这n个物品排好序.第x次我们找到第x矮的物品位置p[x],并且把x到p[x]中间的物品翻转.如果有多个一样 ...

  7. 【洛谷P3369】普通平衡树(splay)

    emmmmm直接丢代码了 #include<iostream> #include<cstdio> #include<cstring> #include<str ...

  8. 洛谷P3809 后缀排序【后缀数组】【模板】

    题目背景 这是一道模板题. 题目描述 读入一个长度为 nn 的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置.位置编 ...

  9. 洛谷P2497:基站建设(splay、斜率优化)

    所谓splay斜率优化dp,就是利用splay和斜率对dp进行优化 (逃) 解析 在斜优的时候,有时我们会发现我们插入的点的横坐标并不单调 这个时候我们就无法利用单调队列维护凸包了 这时,我们就要请出 ...

最新文章

  1. 【贪心】Google Code Jam Round 1A 2018 Waffle Choppers
  2. 【求推荐】优化SAP使用效率的RPA工具推荐
  3. javaWeb项目 IDEA中导入eclipes项目的方法。maven多模块项目(父子模块)与普通的web项目导入
  4. Delphi格式化函数Format、FormatDateTime和FormatFloat详解
  5. 黑马程序员——GUI篇
  6. 案例精解:insert逻辑读暴增至20万,只因Oracle Recyclebin过大
  7. 安卓应用安全指南 4.2.1 创建/使用广播接收器 示例代码
  8. 【字符串全排列】LeetCode 567. Permutation in String
  9. 如何设计一个本地缓存,涨姿势了!
  10. data为long 怎么设置vue_vue.js入门
  11. 广东2022年下半年系统集成项目管理工程师上午真题及答案解析
  12. cad导出pdf_CAD批量打印插件神器CAD导出PDF插件
  13. keras 的dot、multiply区别
  14. 淘宝 京东 拼多多 唯品会返利 公众号开发
  15. STM32F103系列控制的OLED IIC 4针
  16. teamviewer13试用期已到期,错装商业版怎么还原成个人版?
  17. 发送网页内容到onenote_将网页中的信息快速添加到OneNote笔记本的方法
  18. R语言绘图:条形图——barplot
  19. 国内外镜像下载合集(详细最终版)
  20. maplesim matlab,MapleSim 2020

热门文章

  1. 中国移动利润大幅上涨后,降低5G套餐,却悄悄提高固网宽带价格
  2. 计算机教育随笔,计算机信息教育随笔
  3. 网银互联获杭州市云计算协会理事单位授牌
  4. 职业篇-忠告2-努力工作是成就充实人生不可或缺的要义
  5. I.MX6ULL ARM驱动开发---设备树下的platfrom设备驱动
  6. 关于javascript的unescape()函数
  7. java使用selenium实现模拟浏览器操作API大全 模拟登录
  8. 免费服务器硬件资源管理工具,wgcloud 国人免费版服务器资源监控工具
  9. linux超神之旅二
  10. 关于csv文件导入excel出现“此文本文件包含的数据无法放置在一个工作表中。如要继续导入可容纳的数据,请单击确定。。。”的错误