• codevs1743 反转卡片


                             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旋转区间

    之前写了bzoj3223: Tyvj 1729 文艺平衡树

    但是理解还不够深刻

    还没能透彻理解区间旋转

    因此刚开始找左数第一个数时写错了

    直接写成了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;
    }


  • 相关阅读:
    duilib clabelui 属性
    C++ 时间戳和时间的互相转换
    VS提示已有主体显示 的error解决办法
    Webrtc createoffer以后没有 onsuccess的回调
    VS error LNK2019: 无法解析的外部符号 _AcquireCredentialsHandleA
    VS LNK2019 无法解析的外部符号_GetAdaptersAddresses@20 错误解决办法
    duilib xml布局文件的属性设置
    Doris安装
    Oozie初探
    Notepad++ 常规骚操作
  • 原文地址:https://www.cnblogs.com/Brian551/p/7353036.html
Copyright © 2020-2023  润新知