牛客网暑期ACM多校训练营(第三场)C(Shuffle Cards)

题目描述 
Eddy likes to play cards game since there are always lots of randomness in the game. For most of the cards game, the very first step in the game is shuffling the cards. And, mostly the randomness in the game is from this step. However, Eddy doubts that if the shuffling is not done well, the order of the cards is predictable! 

To prove that, Eddy wants to shuffle cards and tries to predict the final order of the cards. Actually, Eddy knows only one way to shuffle cards that is taking some middle consecutive cards and put them on the top of rest. When shuffling cards, Eddy just keeps repeating this procedure. After several rounds, Eddy has lost the track of the order of cards and believes that the assumption he made is wrong. As Eddy's friend, you are watching him doing such foolish thing and easily memorizes all the moves he done. Now, you are going to tell Eddy the final order of cards as a magic to surprise him.

Eddy has showed you at first that the cards are number from 1 to N from top to bottom.

For example, there are 5 cards and Eddy has done 1 shuffling. He takes out 2-nd card from top to 4-th card from top(indexed from 1) and put them on the top of rest cards. Then, the final order of cards from top will be [2,3,4,1,5].
输入描述:
The first line contains two space-separated integer N, M indicating the number of cards and the number of shuffling Eddy has done.
Each of following M lines contains two space-separated integer pi, si indicating that Eddy takes pi-th card from top to (pi+si-1)-th card from top(indexed from 1) and put them on the top of rest cards.


1 ≤ N, M ≤ 105
1 ≤ pi ≤ N
1 ≤ si ≤ N-pi+1
输出描述:
Output one line contains N space-separated integers indicating the final order of the cards from top to bottom.

输入

5 1
2 3
输出

2 3 4 1 5

输入

5 2
2 3
2 3
输出

3 4 1 2 5

输入

5 3
2 3
1 4
2 4
输出

3 4 1 5 2

题意:给出n,m表示1到n的按顺序排列的数和m次操作。然后每次操作给出l和len,将从l及其后面len长度的数转移到开头组成新序列。多次操作问最终弄结果。

思路两种解法

1,(编译器版本要高)

来自:https://blog.csdn.net/b_r_e_a_d/article/details/81235449

#include <ext/rope>
using namespace __gnu_cxx;
int a[1000];
rope<int> x;
rope<int> x(a,a + n);
rope<int> a(x);

x->at(10);
x[10];
x->push_back(x)     // 在末尾添加x
x->insert(pos,x)    // 在pos插入x
x->erase(pos,x)     // 从pos开始删除x个
x->replace(pos,x)   // 从pos开始换成x
x->substr(pos,x)    // 提取pos开始往后x个

#include<bits/stdc++.h>
#include<ext/rope>
using namespace std;
using namespace __gnu_cxx;
#define LL long long int
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
int n,m;
int l,r;
rope<int>rop;
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        rop.clear();
        for(int i=1;i<=n;i++)
            rop.push_back(i);
        while(m--)
        {
            scanf("%d%d",&l,&r);
            rop.insert(0,rop.substr(l-1,r));
            rop.erase(l+r-1,r);
        }
        for(int i=0;i<n;i++)
        {
            if(!0) printf(" ");
            printf("%d",rop[i]);
        }
        printf("\n");
    }
    return 0;
}

2,(splay树)

几乎花了一天的时间学习平衡树,对于这道题就是个模版。

#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#include <cstring>
#define Stop system("pause")
#define type int
#define MAXN 2000005
#define MAXL 100005
#define INF (1<<30)
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
using namespace std;
struct Splay_Tree
{
    struct Node//节点
    {
        Node *c[2],*p;
        int value,size,Min,lazy;
        bool rev;
    }*root,*null,*lb,*rb,S[MAXN];
    int scnt;
    //inline int max(int a,int b) {return a>b?a:b;}
    inline Node * NewNode(int value,Node *p)//插入新节点
    {
        Node *e=S+(++scnt);
        e->value=value;
        e->size=1;
        e->p=p;
        e->Min=value;
        e->lazy=0;
        e->rev=false;
        e->c[0]=e->c[1]=null;
        return e;
    }
    inline void Update(Node *p)//更新节点信息
    {
        if (p==null)
            return;
        p->size=p->c[0]->size+p->c[1]->size+1;
        p->Min=min(p->value,min(p->c[0]->Min,p->c[1]->Min));
    }
    inline void PushDown(Node *x)//更新标记
    {
        if(x==null)
            return;
        if(x->rev)
        {
            x->rev=false;
            Node *t=x->c[0];
            x->c[0]=x->c[1];
            x->c[1]=t;
            x->c[0]->rev=!x->c[0]->rev;
            x->c[1]->rev=!x->c[1]->rev;
            //int w=x->ll; x->ll=x->rr; x->rr=w;
        }
        if(x->lazy)
        {
            int w=x->lazy;
            x->value+=w;
            x->Min+=w;
            x->c[0]->lazy+=w;
            x->c[1]->lazy+=w;
            x->lazy=0;
        }
    }
    inline void Rotate(Node *x,int k)//左旋 k=0;右旋 k=1;
    {
        Node *y=x->p;
        PushDown(x->c[0]);
        PushDown(x->c[1]);
        PushDown(y->c[!k]);
        y->c[k]=x->c[!k];
        y->c[k]->p=y;
        x->p=y->p;
        if(y->p->c[0]==y)
            y->p->c[0]=x;
        else
            y->p->c[1]=x;
        y->p=x;
        x->c[!k]=y;
        Update(y);
        Update(x);
        if(root==y)
            root=x;
    }
    inline void Splay(Node *x,Node *y)//伸展
    {
        PushDown(x);
        while(x->p!=y)
        {
            if(x->p->p==y)
            {
                if(x->p->c[0]==x)
                    Rotate(x,0);
                else
                    Rotate(x,1);
            }
            else if(x->p->p->c[0]==x->p)
            {
                if(x->p->c[0]==x)
                    Rotate(x->p,0),Rotate(x,0);
                else
                    Rotate(x,1),Rotate(x,0);
            }
            else
            {
                if(x->p->c[1]==x)
                    Rotate(x->p,1),Rotate(x,1);
                else
                    Rotate(x,0),Rotate(x,1);
            }
        }
        Update(x);
    }
    inline void Select(int k,Node *y)
    {
        Node *x=root;
        PushDown(x);
        while(k!=x->c[0]->size+1)
        {
            if(k<=x->c[0]->size)
                x=x->c[0];
            else
            {
                k-=x->c[0]->size+1;
                x=x->c[1];
            }
            PushDown(x);
        }
        Splay(x,y);
    }
    inline void MakeTree(int l,int r,type C[],Node *p,int side)
    {
        if(l>r)
            return;
        int mid=(l+r)>>1;
        Node *x;
        x=NewNode(C[mid],p);
        p->c[side]=x;
        MakeTree(l,mid-1,C,x,0);
        MakeTree(mid+1,r,C,x,1);
        Update(x);
    }
    inline void Insert(int pos,int cnt,type C[])//在pos后插入长度为cnt的区间
    {
        Select(pos+1,null);
        Select(pos+2,root);
        MakeTree(1,cnt,C,root->c[1],0);
        Splay(root->c[1]->c[0],null);
    }
    inline void Add(int pos,int cnt,type value)//对pos后长度为cnt的区间中的每个值都增加value
    {
        Select(pos,null);
        Select(pos+cnt+1,root);
        root->c[1]->c[0]->lazy+=value;
        Splay(root->c[1]->c[0],null);
    }
    inline void Delete(int pos,int cnt)//删除pos后长度为cnt的区间
    {
        Select(pos,null);
        Select(pos+cnt+1,root);
        root->c[1]->c[0]=null;
        Splay(root->c[1],null);
    }
    inline void Reverse(int pos,int cnt)//旋转pos后长度为cnt的区间
    {
        Select(pos,null);
        Select(pos+cnt+1,root);
        root->c[1]->c[0]->rev=!root->c[1]->c[0]->rev;
        Splay(root->c[1]->c[0],null);
    }
    inline void Revolve(int a,int b)//将[a,b]区间向右旋转k步
    {
        int A=1;
        int B=a-1;
        int C=a+b-1;                  //转化成交换区间[A,B],[B+1,C];
        Node *p1,*p2,*p3,*p4;
 
        Select(A,null);
        p1=root;        //A-1;
        Select(C+2,null);
        p2=root;      //C+1;
        Select(A+1,null);
        p3=root;      //A;
        Select(B+1,null);
        p4=root;      //B;
 
        Select(A,null);                 //将A-1伸展成root
        Select(C+2,p1);                 //将C+1伸展到A-1的右边
        Select(B+1,p2);                 //将B伸展到C+1的左边
        Node *x,*y;
 
        x=p4->c[1];                     //把b的右子树切断,挂在a的左边
        p4->c[1]=null;
 
        p3->c[0]=x;
        Splay(p3,null);                 //把a伸展为root,一路更新即可
    }
    inline type GetMin(int pos,int cnt)//获得pos后长度为cnt的区间的最小值
    {
        Select(pos,null);
        Select(pos+cnt+1,root);
        PushDown(root->c[1]->c[0]);
        return root->c[1]->c[0]->Min;
    }
    void Index(int pos)
    {
        Select(pos+1,null);
        printf("*%d\n",root->value);
    }
    inline void Print()//打印区间
    {
        int i;
        for(i=1; i<scnt-1; i++)
            Index(i);
    }
    inline void Init()
    {
        scnt=-1;
        null=0;
        null=NewNode(INF,0);
        null->size=0;
        lb=root=NewNode(INF,null);
        rb=root->c[1]=NewNode(INF,root);
        Update(root);
    }
} Splay;
int N,M,pos;
type C[MAXL],ans;
char s[20];
int main()
{
    int i,j,a,b,c,k;
    Splay.Init();
    scanf("%d",&N);
    for(i=1; i<=N; i++)
        C[i]=i;
    Splay.Insert(0,N,C);
 
 
    scanf("%d",&M);
    while(M--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        if (a!=1) Splay.Revolve(a,b);
    }
    for (i=1; i<N; i++)
        printf("%d ",Splay.GetMin(i,1));
    printf("%d\n",Splay.GetMin(N,1));
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值