• codevs 1743 反转卡片 rope or splay


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

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

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

  • 相关阅读:
    PHP 中的 cURL 爬虫实战基础
    PHP的输出缓冲区
    Web网站高并发量的解决方案
    PHP Socket 简单使用
    php无极限分类函数
    PHP单链表的基本操作
    PHP中的10个实用函数
    你真的了解现在的PHP吗?
    国人骄傲,layer.js 搞定所有弹窗
    字典排序
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/8067628.html
Copyright © 2020-2023  润新知