【codevs1743】反转卡片

题目描述 Description

【dzy493941464|yywyzdzr原创】

小A将N张卡片整齐地排成一排,其中每张卡片上写了1~N的一个整数,每张卡片上的数各不相同。

比如下图是N=5的一种情况:3 4 2 1 5

接下来你需要按小A的要求反转卡片,使得左数第一张卡片上的数字是1。操作方法:令左数第一张卡片上的数是K,如果K=1则停止操作,否则将左数第1~K张卡片反转。

第一次(K=3)反转后得到:2 4 3 1 5

第二次(K=2)反转后得到:4 2 3 1 5

第三次(K=4)反转后得到:1 3 2 4 5

可见反转3次后,左数第一张卡片上的数变成了1,操作停止。

你的任务是,对于一种排列情况,计算要反转的次数。你可以假设小A不会让你操作超过100000次。

输入描述 Input Description

第1行一个整数N

第2行N个整数,为1~N的一个全排列。

输出描述 Output Description

仅1行,输出一个整数表示要操作的次数。

如果经过有限次操作仍无法满足要求,输出-1。

样例输入 Sample Input

5

3 4 2 1 5

样例输出 Sample Output

3

数据范围及提示 Data Size & Hint

0<N≤300,000。

题解:两种方法,rope,十分简单的,c++#include<ext/rope>可持久化平衡树,。

   splay,区间旋转在其实就想到了splay吧,每次lg,常数大一些。

   

   红色代表虚点,黑色代表实点,先翻转成这个样子,然后对于根的右子树的左子树的根打上旋转标记

   即可。

   旋转标记

   

代码注释了不少

rope代码

  1. #include<cstring>
  2. #include<cmath>
  3. #include<iostream>
  4. #include<algorithm>
  5. #include<cstdio>
  6. #include<ext/rope>
  7. #include<ext/hash_map>
  8.  
  9. #define N 300007
  10. using namespace std;
  11. using namespace __gnu_cxx;
  12. inline int read()
  13. {
  14. int x=,f=;char ch=getchar();
  15. while(ch<''||ch>''){if (ch=='-')f=-;ch=getchar();}
  16. while(ch>=''&&ch<=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
  17. return x*f;
  18. }
  19.  
  20. int n,ans;
  21. int a[N];
  22. rope<int>s1,s2,t1,t2;
  23.  
  24. void spin(int x)
  25. {
  26. t1=s1.substr(,x);
  27. t2=s2.substr(n-x,x);//后者是长度
  28. s1=t2+s1.substr(x,n-x);
  29. s2=s2.substr(,n-x)+t1;
  30. }
  31. int main()
  32. {
  33. n=read();
  34. for (int i=;i<=n;i++)a[i]=read();
  35. for (int i=;i<=n;i++)s1.push_back(a[i]);
  36. for (int i=;i<=n;i++)s2.push_back(a[n-i+]);
  37. while(s1[]!=)
  38. {
  39. spin(s1[]);
  40. ans++;
  41. if (ans>)
  42. {
  43. printf("-1\n");
  44. return ;
  45. }
  46. }
  47. printf("%d\n",ans);
  48. }

splay代码

  1. #include<cstring>
  2. #include<cmath>
  3. #include<iostream>
  4. #include<algorithm>
  5. #include<cstdio>
  6.  
  7. #define N 300007
  8. using namespace std;
  9. inline int read()
  10. {
  11. int x=,f=;char ch=getchar();
  12. while(ch<''||ch>''){if (ch=='-') f=-;ch=getchar();}
  13. while(ch>=''&&ch<=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
  14. return x*f;
  15. }
  16.  
  17. int n,ans,rt;
  18. int a[N];
  19. int c[N][],fa[N],siz[N],val[N];
  20. bool rev[N];
  21.  
  22. void update(int k)
  23. {
  24. int l=c[k][],r=c[k][];
  25. siz[k]=siz[l]+siz[r]+;
  26. }
  27. void rotate(int x,int &k)
  28. {
  29. int y=fa[x],z=fa[y],l,r;
  30. if (c[y][]==x)l=;else l=;r=l^;
  31. if (y==k) k=x;
  32. else
  33. {
  34. if (c[z][]==y) c[z][]=x;
  35. else c[z][]=x;
  36. }
  37. fa[x]=z,fa[y]=x,fa[c[x][r]]=y;
  38. c[y][l]=c[x][r],c[x][r]=y;
  39. update(y),update(x);
  40. }
  41. void splay(int x,int &p)
  42. {
  43. while(x!=p)
  44. {
  45. int y=fa[x],z=fa[y];
  46. if (y!=p)
  47. {
  48. if (c[y][]==x^c[z][]==y) rotate(x,p);
  49. else rotate(y,p);
  50. }
  51. rotate(x,p);
  52. }
  53. }
  54. void pushdown(int k)
  55. {
  56. int l=c[k][],r=c[k][];
  57. rev[k]^=,rev[l]^=,rev[r]^=;
  58. swap(c[k][],c[k][]);
  59. }
  60. void build(int l,int r,int p)
  61. {
  62. if (l>r) return;
  63. int mid=(l+r)>>;
  64. if (mid<p) c[p][]=mid;
  65. else c[p][]=mid;
  66. siz[mid]=,val[mid]=a[mid],fa[mid]=p;
  67. if (l==r) return;
  68. build(l,mid-,mid),build(mid+,r,mid);
  69. update(mid);
  70. }
  71. int find(int p,int rk)//寻找第rk的位置。
  72. {
  73. if (rev[p]) pushdown(p);
  74. int l=c[p][],r=c[p][];
  75. if (siz[l]+==rk) return p;
  76. else if (siz[l]>=rk) return find(l,rk);
  77. else return find(r,rk-siz[l]-);
  78. }
  79. void spin(int l,int r)
  80. {
  81. int x=find(rt,l),y=find(rt,r+);//因为加了两个虚节点,所以翻转的时候方便,1为虚节点,将2----当前位置+1这一段旋转出来。
  82. splay(x,rt),splay(y,c[x][]);//这样根的右子树的左子树就是所求区间。
  83. int z=c[y][];
  84. rev[z]^=;//在这个节点上打上标记,可以想一下,现在树是什么样子的。
  85. }
  86. int main()
  87. {
  88. n=read();
  89. for (int i=;i<=n;i++) a[i+]=read();
  90. build(,n+,),rt=(+n+)>>;//0只是虚的点,没有用的,1和n+2是哨兵,一线段树的形式建立splay先。
  91. while(val[find(rt,)]!=)//第二个是第一个数
  92. {
  93. ans++;
  94. spin(,val[find(rt,)]);
  95. if (ans>)
  96. {
  97. printf("-1\n");
  98. return ;
  99. }
  100. }//操作直到第一个是1。
  101. printf("%d\n",ans);
  102. }

   发现手写splay快,常数大但是比c++的大部分的stl还是快的,stl没有开O3,O2

   是很慢的,而且可持久化平衡树更强大,就需要更大的代价。

codevs 1743 反转卡片 rope or splay的更多相关文章

  1. Codevs 1743 反转卡片(splay)

    1743 反转卡片 时间限制: 2 s 空间限制: 256000 KB 题目等级 : 大师 Master 题目描述 Description [dzy493941464|yywyzdzr原创] 小A将N ...

  2. codevs 1743 反转卡片

    题目描述 Description [dzy493941464|yywyzdzr原创] 小A将N张卡片整齐地排成一排,其中每张卡片上写了1~N的一个整数,每张卡片上的数各不相同. 比如下图是N=5的一种 ...

  3. [codevs1743]反转卡片

    [codevs1743]反转卡片 试题描述 [dzy493941464|yywyzdzr原创] 小A将N张卡片整齐地排成一排,其中每张卡片上写了1~N的一个整数,每张卡片上的数各不相同. 比如下图是N ...

  4. 【codevs1743】 反转卡片

    http://codevs.cn/problem/1743/ (题目链接) 题意 给出一个序列{a1,a2,a3···},要求维护这样一种操作:将前a1个数反转,若第a1等于1,则停止操作. Solu ...

  5. 2018牛客网暑期ACM多校训练营(第三场) H - Shuffle Cards - [splay伸展树][区间移动][区间反转]

    题目链接:https://www.nowcoder.com/acm/contest/141/C 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言524288K ...

  6. ●Splay的一些题

    ●个人感觉: 代码长: 函数多: (很套路): (很强的Splay,无愧于“区间王”) ●NOI2005维修数列 一个可以当模板学习的题,包含了众多操作(函数): 区间插入,删除,更新,翻转,询问信息 ...

  7. POJ 3580 - SuperMemo - [伸展树splay]

    题目链接:http://poj.org/problem?id=3580 Your friend, Jackson is invited to a TV show called SuperMemo in ...

  8. Splay基本操作

    我们以一道题来引入吧! 传送门 题目说的很清楚,我们的数据结构要支持:插入x数,删除x数,查询数的排名和排名为x的数,求一个数前驱后继. 似乎用啥现有的数据结构都很难做到在O(nlogn)的复杂度中把 ...

  9. 【集训第四天·继续刷题】之 lgh怒刚ypj

    继续水题,终于完全掌握了伸展树了,好心痛QAQ. 1.codevs1343 蚱蜢 区间最大值查询+单点移动 最大值查询维护一个mx数组就行,单点移动么,先删除在插入 CODE: /* PS: 比较ma ...

随机推荐

  1. 服务器php-cgi.exe进程过多,导致CPU占用100%的解决方法

    再使用iis服务器中经常会出现php-cgi.exe进程过多,导致CPU占用100%,最终造成网站运行过慢甚至卡死的情况,重启iis会好一会,过一段时间久出现这种情况,为什么会出现这种情况呢,应该怎么 ...

  2. RabbitMQ八:交换机类型Exchange Types--Topic介绍

    前言 上一章节,我们说了两个类型,本章我们说一下其三:Topic Exchange Topic Exchange  Topic Exchange – 将路由键和某模式进行匹配.此时队列需要绑定要一个模 ...

  3. Java并发——结合CountDownLatch源码、Semaphore源码及ReentrantLock源码来看AQS原理

    前言: 如果说J.U.C包下的核心是什么?那我想答案只有一个就是AQS.那么AQS是什么呢?接下来让我们一起揭开AQS的神秘面纱 AQS是什么? AQS是AbstractQueuedSynchroni ...

  4. 批量部署Hadoop集群环境(1)

    批量部署Hadoop集群环境(1) 1. 项目简介: 前言:云火的一塌糊涂,加上自大二就跟随一位教授做大数据项目,所以很早就产生了兴趣,随着知识的积累,虚拟机已经不能满足了,这次在服务器上以生产环境来 ...

  5. Android中进程与线程及如何在子线程中操作UI线程

    1. Android进程 一个应用程序被启动时,系统默认创建执行一个叫做"main"的线程.这个线程也是你的应用与界面工具包(android.widget和android.view ...

  6. Linux系统结构与终端控制台

    Linux系统结构与终端控制台 作者:Vashon 时间:20150418 以下主要是对Linux系统终端控制台切换及基本操作的范例,其他的理论就不多说了,直接进入实践部分. Starting.... ...

  7. 消息中间件与RPC的区别

    消息中间件和消息通信与RPC各自具有怎样的优势,如何互补消息中间件主要实现的是异步.弹性消息以及队列,弹性消息有时可以借助于外存从而一定程度上可以实现峰值缓存,有效均衡服务器端压力,同时消息可以进行一 ...

  8. COGS 827. [Tyvj Feb11] 网站计划

    输入文件:web.in   输出文件:web.out   简单对比时间限制:1 s   内存限制:128 MB 描述 Description     Tyvj的Admin--zhq同学将在寒假开始实行 ...

  9. Django展示第一个网页

    展示一个网页需要三部分组成: urls.py -- 指定网址与对应的视图 views.py -- 创建试图以及指定对应的模板 template/*.html -- 对应的模板 一.urls.py ur ...

  10. Eclipse--java.lang.OutOfMemoryError: PermGen space

    这一段时间,Eclipse总是死掉,几乎是稍微操作快一点就会死掉,几分钟一次,搞得人郁闷至极.浪费了不少时间,在网上搜了下,看到很多朋友也出现类似的情况,在网上求救,但是网上的办法都只是说通过修改ec ...