1743 反转卡片
时间限制: 2 s
空间限制: 256000 KB
题目等级 : 大师 Master
题解
题目描述 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。
一道splay旋转区间
但是理解还不够深刻
还没能透彻理解区间旋转
因此刚开始找左数第一个数时写错了
直接写成了tr[2].v(1是虚拟结点,翻转用的)
而splay旋转时是直接修改树的左右孩子(感觉是类似于指针一样的东西,就是指向左右孩子的树根)
所以tr[2].v可能会转到其他地方
所以要先用find函数找到排名为2的结点的位置
嗯,理解深刻多了
(如有错误请大神指教)
Ps:Sheldon帅炸啦!!!!!!
#include<cstdio>
#include<iostream>
const int N=300050;
struct node
{
int fa,c[2],size,v,lazy;
}tr[N];
int n,root;
void pushup(int k)
{
tr[k].size=tr[tr[k].c[0]].size+tr[tr[k].c[1]].size+1;
}
void pushdown(int k)
{
if(tr[k].lazy)
{
std::swap(tr[k].c[0],tr[k].c[1]);
tr[tr[k].c[0]].lazy^=1;
tr[tr[k].c[1]].lazy^=1;
tr[k].lazy=0;
}
}
void build(int l,int r,int fa)
{
if(l>r) return ;
if(l==r)
{
tr[l].fa=fa;tr[l].size=1;
if(l<fa) tr[fa].c[0]=l;
else tr[fa].c[1]=l;
}
int mid=(l+r)>>1;
build(l,mid-1,mid);build(mid+1,r,mid);
tr[mid].fa=fa;pushup(mid);
if(mid<fa) tr[fa].c[0]=mid;
else tr[fa].c[1]=mid;
}
void rotate(int x,int &k)
{
int y=tr[x].fa,z=tr[y].fa, l,r;
if(tr[y].c[0]==x)l=0;
else l=1;
r=l^1;
if(y==k)k=x;
else
{
if(tr[z].c[0]==y)tr[z].c[0]=x;
else tr[z].c[1]=x;
}
tr[x].fa=z; tr[y].fa=x;
tr[tr[x].c[r]].fa=y;
tr[y].c[l]=tr[x].c[r];
tr[x].c[r]=y;
pushup(y); pushup(x);
}
void splay(int x,int &k)
{
while(x!=k)
{
int y=tr[x].fa,z=tr[y].fa;
if(y!=k)
{
if((tr[y].c[0]==x)^(tr[z].c[0]==y)) rotate(x,k);
else rotate(y,k);
}
rotate(x,k);
}
}
int find(int k,int rank)
{
pushdown(k);
if(tr[tr[k].c[0]].size+1==rank) return k;
if(tr[tr[k].c[0]].size+1>rank) return find(tr[k].c[0],rank);
else return find(tr[k].c[1],rank-tr[tr[k].c[0]].size-1);
}
void dfs(int ro)
{
pushdown(ro);
if(tr[ro].c[0])dfs(tr[ro].c[0]);
if(ro!=1&&ro!=n+2)printf("%d ",tr[ro].v);
if(tr[ro].c[1])dfs(tr[ro].c[1]);
}
void rever(int l,int r)
{
int x=find(root,l);
splay(x,root);
int y=find(root,r+2);
splay(y,tr[root].c[1]);
tr[tr[y].c[0]].lazy^=1;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&tr[i+1].v);
build(1,n+2,n+5);//该序列为 2 ~ n+1
//额外节点为 1 和 n+2
root=tr[n+5].c[0];
for(int ans=0;ans<=100000;ans++)
{
int k=tr[find(root,2)].v;
if(k!=1) rever(1,k);
else
{
printf("%d
",ans);
return 0;
}
}
printf("-1
");
return 0;
}