【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代码

 #include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<ext/rope>
#include<ext/hash_map> #define N 300007
using namespace std;
using namespace __gnu_cxx;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if (ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x*f;
} int n,ans;
int a[N];
rope<int>s1,s2,t1,t2; void spin(int x)
{
t1=s1.substr(,x);
t2=s2.substr(n-x,x);//后者是长度
s1=t2+s1.substr(x,n-x);
s2=s2.substr(,n-x)+t1;
}
int main()
{
n=read();
for (int i=;i<=n;i++)a[i]=read();
for (int i=;i<=n;i++)s1.push_back(a[i]);
for (int i=;i<=n;i++)s2.push_back(a[n-i+]);
while(s1[]!=)
{
spin(s1[]);
ans++;
if (ans>)
{
printf("-1\n");
return ;
}
}
printf("%d\n",ans);
}

splay代码

 #include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstdio> #define N 300007
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if (ch=='-') f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x*f;
} int n,ans,rt;
int a[N];
int c[N][],fa[N],siz[N],val[N];
bool rev[N]; void update(int k)
{
int l=c[k][],r=c[k][];
siz[k]=siz[l]+siz[r]+;
}
void rotate(int x,int &k)
{
int y=fa[x],z=fa[y],l,r;
if (c[y][]==x)l=;else l=;r=l^;
if (y==k) k=x;
else
{
if (c[z][]==y) c[z][]=x;
else c[z][]=x;
}
fa[x]=z,fa[y]=x,fa[c[x][r]]=y;
c[y][l]=c[x][r],c[x][r]=y;
update(y),update(x);
}
void splay(int x,int &p)
{
while(x!=p)
{
int y=fa[x],z=fa[y];
if (y!=p)
{
if (c[y][]==x^c[z][]==y) rotate(x,p);
else rotate(y,p);
}
rotate(x,p);
}
}
void pushdown(int k)
{
int l=c[k][],r=c[k][];
rev[k]^=,rev[l]^=,rev[r]^=;
swap(c[k][],c[k][]);
}
void build(int l,int r,int p)
{
if (l>r) return;
int mid=(l+r)>>;
if (mid<p) c[p][]=mid;
else c[p][]=mid;
siz[mid]=,val[mid]=a[mid],fa[mid]=p;
if (l==r) return;
build(l,mid-,mid),build(mid+,r,mid);
update(mid);
}
int find(int p,int rk)//寻找第rk的位置。
{
if (rev[p]) pushdown(p);
int l=c[p][],r=c[p][];
if (siz[l]+==rk) return p;
else if (siz[l]>=rk) return find(l,rk);
else return find(r,rk-siz[l]-);
}
void spin(int l,int r)
{
int x=find(rt,l),y=find(rt,r+);//因为加了两个虚节点,所以翻转的时候方便,1为虚节点,将2----当前位置+1这一段旋转出来。
splay(x,rt),splay(y,c[x][]);//这样根的右子树的左子树就是所求区间。
int z=c[y][];
rev[z]^=;//在这个节点上打上标记,可以想一下,现在树是什么样子的。
}
int main()
{
n=read();
for (int i=;i<=n;i++) a[i+]=read();
build(,n+,),rt=(+n+)>>;//0只是虚的点,没有用的,1和n+2是哨兵,一线段树的形式建立splay先。
while(val[find(rt,)]!=)//第二个是第一个数
{
ans++;
spin(,val[find(rt,)]);
if (ans>)
{
printf("-1\n");
return ;
}
}//操作直到第一个是1。
printf("%d\n",ans);
}

   发现手写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. android 防止bitmap 内存溢出

    在android开发过程中经常会处理网络图片发送内存溢出,那么怎么解决这种问题? 思路: 下载到本地 通过网络获取和文件下载存放到手机中目录 代码: // 获取网络 public InputStrea ...

  2. Bundle的用法

    一.API文档说明 1.介绍 用于不同Activity之间的数据传递 1.重要方法 clear():清除此Bundle映射中的所有保存的数据. clone():克隆当前Bundle containsK ...

  3. 应用-如何使不同的企业使用独自的数据源。使用ejb3.0+jboss6.2EAP+JPA

    摘要:                如何使不同的企业使用独自的数据源.使用ejb3.0+jboss6.2EAP+JPA10C应用系统被多个企业同时使用,为了提供个性化服务,如何使不同的企业使用独自的 ...

  4. Cognos报表验证(添加字段)

    1.打开后台Cognos 链接远程后台Cognos 2.打开要验证的报表 3.给右边的sql语句加个空格或者换行点击验证 4.查看业务视图中是否已经添加该字段 双击维度或者度量(添加字段所在的分类) ...

  5. 51nod 1417 天堂里的游戏

    基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题  收藏  关注 多年后,每当Noder看到吉普赛人,就会想起那个遥远的下午. Noder躺在草地上漫无目的的张望,二 ...

  6. cluvfy comp命令用法

    1.获取集群验证工具cluvfy的帮助信息 grid@rac1:/home/grid>cluvfy -help USAGE: cluvfy [ -help ] cluvfy stage { -l ...

  7. Android Studio 中文件查询方法总结

    搜索单词 Windows: Ctrl + F Mac   : Cmd + F 会在当前激活的文件上查询输入的关键字,以高亮显示 跳转行 Windows: Ctrl + L Mac   : Cmd + ...

  8. java工作流activiti的步骤

    链接:activiti 表名称的解释 工作流从流程定义到创建一个流程实例完成执行步骤(省略bpmn的画法) 工作流的所有操作都是使用流程引擎来进行操作的,流程引擎只是存储流程的过程,而不存储具体的业务 ...

  9. pip和pip3安装、升级、版本查看及遇到的问题

    pip的安装 问题一 sudo apt-get install python-pip #安装pip sudo pip install --upgrade pip -i http://mirrors.a ...

  10. vue iview render里面 没有双向绑定 renderHeader 要序列化 反序列 一下

    vue iview render里面 没有双向绑定 renderHeader 要序列化 反序列 一下 renderHeader: (h, params) => { return [ h('Rad ...