【jzoj3599】【CQOI2014】【排序机械臂】【splay】

题目大意

这里写图片描述

解题思路

先按val为第一关键字,编号为第二关键字,从小到大排序,离散化。然后在末尾加入一个无穷大,建一棵splay,维护size和min的编号,支持求后继和区间翻转。
时刻保持上一个翻转的点为根,将将要翻转的挂在根下面,把将要翻转的的后继挂在根下面,然后对其左子树区间翻转。由于将要翻转的一定在其左子树的最右边,编号就是左子树的size加根及其左子树的点数。

code

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LF double
#define LL long long
#define Min(a,b) ((a<b)?a:b)
#define Max(a,b) ((a>b)?a:b)
#define Fo(i,j,k) for(int i=j;i<=k;i++)
#define Fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const Mxn=1e5;
int N,Val[Mxn+9],Size[Mxn+9],Mi[Mxn+9],Swap[Mxn+9],Fa[Mxn+9],Son[Mxn+9][2]
    ,A[Mxn+9];
void Retag(int Now){
    if(Now&&Swap[Now]){
        swap(Son[Now][0],Son[Now][1]);
        Swap[Son[Now][0]]^=1;
        Swap[Son[Now][1]]^=1;
        Swap[Now]=0;
    }
}
int Side(int Now,int F){
    return Son[F][1]==Now;
}
void Update(int Now){
    Size[Now]=Size[Son[Now][0]]+Size[Son[Now][1]]+1;
    Mi[Now]=(Val[Now]<=Val[Mi[Son[Now][0]]])?Now:Mi[Son[Now][0]];
    Mi[Now]=(Val[Mi[Now]]<=Val[Mi[Son[Now][1]]])?Mi[Now]:Mi[Son[Now][1]];
}
void Rotate(int Now){
    Retag(Now);
    int F=Fa[Now],T=Side(Now,F);
    Son[F][T]=Son[Now][!T];
    Fa[Son[Now][!T]]=F;
    Son[Fa[F]][Side(F,Fa[F])]=Now;
    Fa[Now]=Fa[F];
    Son[Now][!T]=F;
    Fa[F]=Now;
    Update(F);
    Update(Now);
}
void Splay(int Now,int Top){
    while(Fa[Now]!=Top){
        if(Fa[Fa[Now]]==Top)Retag(Fa[Now]),Rotate(Now);
        else{
            Retag(Fa[Fa[Now]]),Retag(Fa[Now]);
            if(Side(Now,Fa[Now])==Side(Fa[Now],Fa[Fa[Now]]))
                Rotate(Fa[Now]),Rotate(Now);
            else Rotate(Now),Rotate(Now);
        }
    }
}
int Next(int Now){
    Retag(Now);Now=Son[Now][1];Retag(Now);
    while(Son[Now][0]){
        Now=Son[Now][0];
        Retag(Now);
    }
    return Now;
}
bool Cmp(int X,int Y){return (Val[X]<Val[Y])||((Val[X]==Val[Y])&&(X<Y));}
int main(){
    freopen("d.in","r",stdin);
    freopen("d.out","w",stdout);
    scanf("%d",&N);
    Fo(i,1,N){
        scanf("%d",&Val[i]),A[i]=i;
        Fa[i]=i-1;
        Son[i-1][1]=i;
    }
    sort(A+1,A+N+1,Cmp);
    Fo(i,1,N)Val[A[i]]=i;
    Fa[N+1]=N;
    Son[N][1]=N+1;Mi[N+1]=N+1;Size[N+1]=1;
    Val[0]=Val[N+1]=1e9;
    Fd(i,N,1)Mi[i]=(Val[i]<Val[Mi[i+1]])?i:Mi[i+1],Size[i]=Size[i+1]+1;
    printf("%d ",Mi[1]);
    int Tmp,Pre,Now;
    Splay(Tmp=Son[Pre=Mi[1]][1],0);
    Swap[Son[Tmp][0]]^=1;
    Fo(i,1,N-2){
        Splay(Pre,0);
        Splay(Now=Mi[Son[Pre][1]],Pre);
        Splay(Tmp=Next(Now),Pre);
        printf("%d ",N+1-Size[Tmp]+Size[Son[Tmp][0]]);
        Swap[Son[Tmp][0]]^=1;
        Pre=Now;
    }
    printf("%d ",N);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值