zoukankan      html  css  js  c++  java
  • 2018牛客网暑期ACM多校训练营(第三场)C Shuffle Cards(可持久化平衡树/splay)

    题意

    牌面初始是1到n,进行m次洗牌,每次抽取一段放到最前面。求最后的序列。

    分析

    神操作!!!比赛时很绝望,splay技能尚未点亮,不知道怎么用。

    殊不知,C++库里有rope神器,即块状链表。

    基础函数

    #include <ext/rope>
    using namespace __gnu_cxx;
    
    rope test;
    
    test.push_back(x);//在末尾添加x
    test.insert(pos,x);//在pos插入x  
    test.erase(pos,x);//从pos开始删除x个
    test.copy(pos,len,x);//从pos开始到pos+len为止用x代替
    test.replace(pos,x);//从pos开始换成x
    test.substr(pos,x);//提取pos开始x个
    test.at(x)/[x];//访问第x个元素

    有了上面的函数,就解决这道题了(狗头。

    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<queue>
    #include<vector>
    #include<cstdio>
    #include<algorithm>
    #include<map>
    #include<set>
    #include<ext/rope>
    #define rep(i,e) for(int i=0;i<(e);i++)
    #define rep1(i,e) for(int i=1;i<=(e);i++)
    #define repx(i,x,e) for(int i=(x);i<=(e);i++)
    #define X first
    #define Y second
    #define PB push_back
    #define MP make_pair
    #define mset(var,val) memset(var,val,sizeof(var))
    #define scd(a) scanf("%d",&a)
    #define scdd(a,b) scanf("%d%d",&a,&b)
    #define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c)
    #define pd(a) printf("%d
    ",a)
    #define scl(a) scanf("%lld",&a)
    #define scll(a,b) scanf("%lld%lld",&a,&b)
    #define sclll(a,b,c) scanf("%lld%lld%lld",&a,&b,&c)
    #define IOS ios::sync_with_stdio(false);cin.tie(0)
    #define lc idx<<1
    #define rc idx<<1|1
    #define rson mid+1,r,rc
    #define lson l,mid,lc
    
    using namespace std;
    typedef long long ll;
    int read() {
        int x = 0;
        char c = getchar();
        while (c < '0' || c > '9')c = getchar();
        while (c >= '0' && c <= '9') {
            x = x * 10 + c - '0';
            c = getchar();
        }
        return x;
    }
    template <class T>
    void test(T a){cout<<a<<endl;}
    template <class T,class T2>
    void test(T a,T2 b){cout<<a<<" "<<b<<endl;}
    template <class T,class T2,class T3>
    void test(T a,T2 b,T3 c){cout<<a<<" "<<b<<" "<<c<<endl;}
    const int inf = 0x3f3f3f3f;
    const ll INF = 0x3f3f3f3f3f3f3f3fll;
    const ll mod = 1e9+7;
    int T;
    void testcase(){
        printf("Case %d: ",++T);
    }
    const int MAXN = 1e5+10;
    const int MAXM = 30;
    const double eps = 1e-9;
    using namespace __gnu_cxx;
    
    int main() {
    #ifdef LOCAL
        freopen("in.txt","r",stdin);
    #endif // LOCAL
        int n,m;
        n=read();m=read();
        rope<int> ro;
        for(int i=1;i<=n;i++) ro.push_back(i);
        int x,y;
        while(m--){
            x=read();y=read();
            ro=ro.substr(x-1,y)+ro.substr(0,x-1)+ro.substr(y+x-1,n-x-y+1);
        }
        for(int i=0;i<n;i++){
            printf("%d%c",ro[i],(i==n-1?'
    ':' '));
            
        }
        return 0;
    }

     splay实现:区间交换可以用区间翻转来实现

    如 1 2 3 4 5,将区间[2,4]移到前面.。

    可用三次翻转实现

    4 3 2 1 5   翻转[2,4]

    2 3 4 1 5  翻转[1,3]

    2 3 4 1 5  翻转[4,4]

    这样套个模板,注意输出格式

    #include <iostream>
    #include <string.h>
    #include <stdio.h>
    #include <algorithm>
    using namespace std;
    #define Key_value ch[ch[root][1]][0]
    const int MAXN=500010;
    const int INF=0x3f3f3f3f;
    int pre[MAXN],ch[MAXN][2],key[MAXN],size[MAXN];
    int sum[MAXN],rev[MAXN],same[MAXN];
    int lx[MAXN],rx[MAXN],mx[MAXN];
    int root,tot1;
    int s[MAXN],tot2;
    int a[MAXN];
    int n,q;
    //debug部分
    void Treavel(int x)
    {
        if(x)
        {
            Treavel(ch[x][0]);
            printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d key=%2d, size= %2d, sum=%2d,rev=%2d same=%2d lx=%2d rx=%2d mx=%2d
    ",x,ch[x][0],ch[x][1],pre[x],key[x],size[x],sum[x],rev[x],same[x],lx[x],rx[x],mx[x]);
            Treavel(ch[x][1]);
        }
    }
    void debug()
    {
        printf("root%d
    ",root);
        Treavel(root);
    }
    void NewNode(int &r,int father,int k)
    {
        if(tot2)r=s[tot2--];
        else r=++tot1;
        pre[r]=father;
        ch[r][0]=ch[r][1]=0;
        key[r]=k;
        sum[r]=k;
        rev[r]=same[r]=0;
        lx[r]=rx[r]=mx[r]=k;
        size[r]=1;
    }
    void Update_Same(int r,int v)
    {
        if(!r)return;
        key[r]=v;
        sum[r]=v*size[r];
        lx[r]=rx[r]=mx[r]=max(v,v*size[r]);
        same[r]=1;
    }
    void Update_Rev(int r)
    {
        if(!r)return;
        swap(ch[r][0],ch[r][1]);
        swap(lx[r],rx[r]);
        rev[r]^=1;//这里要注意,一定是异或1
    }
    void Push_Up(int r)
    {
        int lson=ch[r][0],rson=ch[r][1];
        size[r]=size[lson]+size[rson]+1;
        sum[r]=sum[lson]+sum[rson]+key[r];
        lx[r]=max(lx[lson],sum[lson]+key[r]+max(0,lx[rson]));
        rx[r]=max(rx[rson],sum[rson]+key[r]+max(0,rx[lson]));
        mx[r]=max(0,rx[lson])+key[r]+max(0,lx[rson]);
        mx[r]=max(mx[r],max(mx[lson],mx[rson]));
    }
    void Push_Down(int r)
    {
        if(same[r])
        {
            Update_Same(ch[r][0],key[r]);
            Update_Same(ch[r][1],key[r]);
            same[r]=0;
        }
        if(rev[r])
        {
            Update_Rev(ch[r][0]);
            Update_Rev(ch[r][1]);
            rev[r]=0;
        }
    }
    void Build(int &x,int l,int r,int father)
    {
        if(l>r)return;
        int mid=(l+r)/2;
        NewNode(x,father,a[mid]);
        Build(ch[x][0],l,mid-1,x);
        Build(ch[x][1],mid+1,r,x);
        Push_Up(x);
    }
    void Init()
    {
        root=tot1=tot2=0;
        ch[root][0]=ch[root][1]=pre[root]=size[root]=same[root]=rev[root]=sum[root]=key[root]=0;
        lx[root]=rx[root]=mx[root]=-INF;
        NewNode(root,0,-1);
        NewNode(ch[root][1],root,-1);
        for(int i=0;i<n;i++) a[i]=i+1;
        Build(Key_value,0,n-1,ch[root][1]);
        Push_Up(ch[root][1]);
        Push_Up(root);
    }
    void Rotate(int x,int kind)
    {
        int y=pre[x];
        Push_Down(y);
        Push_Down(x);
        ch[y][!kind]=ch[x][kind];
        pre[ch[x][kind]]=y;
        if(pre[y])
            ch[pre[y]][ch[pre[y]][1]==y]=x;
        pre[x]=pre[y];
        ch[x][kind]=y;
        pre[y]=x;
        Push_Up(y);
    }
    void Splay(int r,int goal)
    {
        Push_Down(r);
        while(pre[r]!=goal)
        {
            if(pre[pre[r]]==goal)
            {
                Push_Down(pre[r]);
                Push_Down(r);
                Rotate(r,ch[pre[r]][0]==r);
            }
            else
            {
                Push_Down(pre[pre[r]]);
                Push_Down(pre[r]);
                Push_Down(r);
                int y=pre[r];
                int kind=ch[pre[y]][0]==y;
                if(ch[y][kind]==r)
                {
                    Rotate(r,!kind);
                    Rotate(r,kind);
                }
                else
                {
                    Rotate(y,kind);
                    Rotate(r,kind);
                }
            }
        }
        Push_Up(r);
        if(goal==0)root=r;
    }
    int Get_Kth(int r,int k)
    {
        Push_Down(r);
        int t=size[ch[r][0]]+1;
        if(t==k)return r;
        if(t>k)return Get_Kth(ch[r][0],k);
        else return Get_Kth(ch[r][1],k-t);
    }
    
    //在第pos个数后插入tot个数
    void Insert(int pos,int tot)
    {
        for(int i=0;i<tot;i++)scanf("%d",&a[i]);
        Splay(Get_Kth(root,pos+1),0);
        Splay(Get_Kth(root,pos+2),root);
        Build(Key_value,0,tot-1,ch[root][1]);
        Push_Up(ch[root][1]);
        Push_Up(root);
    }
    void erase(int r)
    {
        if(!r)return;
        s[++tot2]=r;
        erase(ch[r][0]);
        erase(ch[r][1]);
    }
    //从第pos个数开始连续删除tot个数
    void Delete(int pos,int tot)
    {
        Splay(Get_Kth(root,pos),0);
        Splay(Get_Kth(root,pos+tot+1),root);
        erase(Key_value);
        pre[Key_value]=0;
        Key_value=0;
        Push_Up(ch[root][1]);
        Push_Up(root);
    }
    //从第pos个数连续开始的tot个数修改为c
    void Make_Same(int pos,int tot,int c)
    {
        Splay(Get_Kth(root,pos),0);
        Splay(Get_Kth(root,pos+tot+1),root);
        Update_Same(Key_value,c);
        Push_Up(ch[root][1]);
        Push_Up(root);
    }
    //反转
    void Reverse(int pos,int tot)
    {
        Splay(Get_Kth(root,pos),0);
        Splay(Get_Kth(root,pos+tot+1),root);
        Update_Rev(Key_value);
        Push_Up(ch[root][1]);
        Push_Up(root);
    }
    //求和
    int Get_Sum(int pos,int tot)
    {
        Splay(Get_Kth(root,pos),0);
        Splay(Get_Kth(root,pos+tot+1),root);
        return sum[Key_value];
    }
    //得到最大和
    int Get_MaxSum(int pos,int tot)
    {
        Splay(Get_Kth(root,pos),0);
        Splay(Get_Kth(root,pos+tot+1),root);
        return mx[Key_value];
    }
    int cnt;
    void Inorder(int r)
    {
        if(!r)return;
        Push_Down(r);
        Inorder(ch[r][0]);
        if(key[r]!=-1) printf("%d%c",key[r],++cnt==n?'
    ':' ');
        Inorder(ch[r][1]);
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        while(scanf("%d%d",&n,&q)==2)
        {
            Init();
    
            int x,y;
            while(q--){
                scanf("%d%d",&x,&y);
                Reverse(1,y+x-1);
                Reverse(1,y);
                Reverse(y+1,x-1);
    
            }
            cnt=0;
            Inorder(root);
        }
        return 0;
    }
  • 相关阅读:
    【leetcode】1365. How Many Numbers Are Smaller Than the Current Number
    【leetcode】1363. Largest Multiple of Three
    【leetcode】1362. Closest Divisors
    【leetcode】1361. Validate Binary Tree Nodes
    【leetcode】1360. Number of Days Between Two Dates
    【leetcode】1359. Count All Valid Pickup and Delivery Options
    【leetcode】1357. Apply Discount Every n Orders
    【leetcode】1356. Sort Integers by The Number of 1 Bits
    ISE应用入门的一些问题
    DDR的型号问题
  • 原文地址:https://www.cnblogs.com/fht-litost/p/9380327.html
Copyright © 2011-2022 走看看