cv1743 反转卡片(splay)

来源:互联网 发布:瘦大腿内侧 知乎 编辑:程序博客网 时间:2024/06/13 00:39
题目描述 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。

tip

find的时候一定要记得push

//这里写代码片#include<cstdio>#include<iostream>#include<iostream>using namespace std;const int N=300010;const int INF=1e9;int size[N],v[N],pre[N],ch[N][2];bool rev[N];int n,a[N],top=0,root;int get(int bh){    return ch[pre[bh]][0]==bh? 0:1;}void update(int bh){    if (!bh) return;    size[bh]=1;    if (ch[bh][0]) size[bh]+=size[ch[bh][0]];    if (ch[bh][1]) size[bh]+=size[ch[bh][1]];}void push(int bh){    if (!bh) return;    if (rev[bh])    {        if (ch[bh][0]) rev[ch[bh][0]]^=1;        if (ch[bh][1]) rev[ch[bh][1]]^=1;        swap(ch[bh][0],ch[bh][1]);        rev[bh]^=1;    }}void rotate(int bh){    int fa=pre[bh];    int grand=pre[fa];    int wh=get(bh);    ch[fa][wh]=ch[bh][wh^1];    pre[ch[fa][wh]]=fa;    ch[bh][wh^1]=fa;    pre[fa]=bh;    pre[bh]=grand;    if (grand) ch[grand][ch[grand][0]==fa? 0:1]=bh;    update(fa);    update(bh);}void down(int bh){    if (pre[bh]) down(pre[bh]);    push(bh);}void splay(int bh,int mb){    down(bh);    for (int fa;(fa=pre[bh])!=mb;rotate(bh))        if (pre[fa]!=mb)           rotate(get(bh)==get(fa)? fa:bh);    if (!mb) root=bh;}int find(int x){    int now=root;    while (1)    {        push(now);        if (size[ch[now][0]]>=x) now=ch[now][0];        else        {            int tmp=(ch[now][0]? size[ch[now][0]]:0);            tmp++;            if (tmp>=x) return now;            x-=tmp;            now=ch[now][1];        }    }}int build(int l,int r,int fa){    if (l>r) return 0;    int now=++top;    int mid=(l+r)/2;    ch[now][0]=build(l,mid-1,now);    ch[now][1]=build(mid+1,r,now);    v[now]=a[mid]; pre[now]=fa; rev[now]=0;    update(now);    return now;}int main(){    scanf("%d",&n);    for (int i=1;i<=n;i++) scanf("%d",&a[i]);    if (a[1]==1)    {        printf("0\n");        return 0;    }    a[0]=-INF; a[n+1]=INF;    root=build(0,n+1,0);    for (int i=1;i<=100000;i++)    {        int xx=find(1);         //0的位置         int pos=find(2);        //1的位置         if (v[pos]==1)        {            printf("%d\n",i-1);            break;        }        int yy=find(v[pos]+2);        if (xx!=root) splay(xx,0);        splay(yy,xx);        int t=ch[ch[root][1]][0];        rev[t]^=1;        update(ch[root][1]); update(root);    }    return 0;}
原创粉丝点击