Codevs1743--反转卡片

在Splay上打反转标记

自己脑补了一下,感觉就是在旋转的时候传递一下标记免得被破坏就可以了。

具体交换左右儿子然后标记下传。

代码:

#include<bits/stdc++.h>
#define MAXN 300005
#define MAXM 3005
#define INF 1000000000
#define MOD 1000000
#define LL long long
using namespace std;

int n;

namespace Splay{
    const int L=0,R=1;
    int root;
    struct Node{
        int son[2],v,sz,par;
        bool turn;
    }x[MAXN];
    
    inline void Push_down(int num) {
        swap(x[num].son[L],x[num].son[R]);x[num].turn^=1;
        x[x[num].son[L]].turn^=1;x[x[num].son[R]].turn^=1;
    }
    inline void rotate(int num,int p) {
        int pa=x[num].par,t=x[num].sz;
        if(x[pa].par) x[x[pa].par].son[x[x[pa].par].son[L]==pa?L:R]=num;
        x[num].sz=x[pa].sz;x[pa].sz-=t-x[x[num].son[p]].sz;
        x[pa].son[p^1]=x[num].son[p];if(x[num].son[p]) {x[x[num].son[p]].par=pa;}
        x[num].son[p]=pa;x[num].par=x[pa].par;x[pa].par=num;
    }
    inline void Splay_N(int num,int gl) {
        int par,ppar;
        while(x[num].par!=gl) {
            if(x[x[x[num].par].par].turn) Push_down(x[x[num].par].par);
            if(x[x[num].par].turn) Push_down(x[num].par);if(x[num].turn) Push_down(num);
            if(x[x[num].par].par==gl) {rotate(num,x[x[num].par].son[L]==num?R:L);break;}
            par=x[x[num].par].son[L]==num?R:L;ppar=x[x[x[num].par].par].son[L]==x[num].par?R:L;
            if(par==ppar) rotate(x[num].par,ppar),rotate(num,par);
            else rotate(num,par),rotate(num,ppar);
        }
        if(!gl) root=num;
    }
    
    int Build_Splay(int l,int r,int fr) {
        if(r<l) return 0;
        int mid=l+r>>1;x[mid].par=fr;
        if(l==r) {x[mid].sz=1;return mid;}
        x[mid].son[L]=Build_Splay(l,mid-1,mid);
        x[mid].son[R]=Build_Splay(mid+1,r,mid);
        x[mid].sz=x[x[mid].son[L]].sz+x[x[mid].son[R]].sz+1;
        return mid;
    }
    void Build() {root=Build_Splay(1,n+1,0);}
    
    int Qurey(int k) {
        int now=root;
        while(true) {
            if(x[now].turn) k=x[now].sz-k+1;
            if(x[x[now].son[L]].sz==k-1) {Splay_N(now,0);return now;}
            if(x[x[now].son[L]].sz<k) {k-=x[x[now].son[L]].sz+1;now=x[now].son[R];}
            else now=x[now].son[L];
        }
    }
    void Turn(int k) {
        Splay_N(Qurey(k),0);
        x[x[root].son[L]].turn^=1;
    }
    bool Check() {
        int t=Qurey(1);t=x[t].v;
        if(t==1) return 0;
        Turn(1+t);
        /*for(int i=1;i<=n;i++) cout<<x[Qurey(i)].v<<" ";
        cout<<endl;*/
        return 1;
    }
}

using namespace Splay;
int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        scanf("%d",&x[i].v);
    }
    Build();
    for(int i=1;i<=100000;i++) {
        if(!Check()) {printf("%d\n",i-1);break;}
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/ihopenot/p/5919813.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值