【bzoj 1552】【bzoj 3506】排序机械臂robotic sort(Splay)

传送门biu~biu~
对原序列建一棵平衡树,用 Findi F i n d i 记录第i小的物品在平衡树上的哪个位置。

#include<bits/stdc++.h>
using namespace std;
int n;
struct data{int x,id,rnk;}a[100005];
bool cmp(data a,data b){return a.x<b.x || (a.x==b.x && a.id<b.id);}
bool cmp_id(data a,data b){return a.id<b.id;}
struct Node{
    Node *fa,*ch[2];
    int siz;
    bool rev_mark;
    Node();
    inline int dir(){
        if(fa->ch[0]==this) return 0;
        if(fa->ch[1]==this) return 1;
        return -1;
    }
    inline void rev();
    inline void pushdown();
    inline void maintain();
}*null=new Node,*root,*Find[100005];
Node :: Node(){
    siz=null?1:0;
    fa=ch[0]=ch[1]=null;
}
inline void Node :: maintain(){
    if(this==null)  return;
    siz=ch[0]->siz+ch[1]->siz+1;
}
inline void Node :: rev(){
    if(this==null)  return;
    swap(ch[0],ch[1]);
    rev_mark^=1;
}
inline void Node :: pushdown(){
    if(this==null)  return;
    if(!rev_mark)   return;
    rev_mark=0;
    ch[0]->rev();ch[1]->rev();
}
void To_pushdown(Node *o){
    if(o->fa!=null)     To_pushdown(o->fa);
    o->pushdown();
}
void buildtree(Node *father,Node *&o,int l,int r){
    if(l>r) return;
    o=new Node();   o->fa=father;
    if(l==r){
        Find[a[l].rnk]=o;
        return;
    }
    int mid=(l+r)>>1;   Find[a[mid].rnk]=o;
    buildtree(o,o->ch[0],l,mid-1);
    buildtree(o,o->ch[1],mid+1,r);
    o->maintain();
}
inline void Rotate(Node *o,int d){
    Node *x=o->ch[d^1];
    x->ch[d]->fa=o; o->ch[d^1]=x->ch[d];
    x->fa=o->fa;    o->fa->ch[o->dir()]=x;
    x->ch[d]=o;     o->fa=x;
    o->maintain();  x->maintain();
}
inline void Splay(Node *o,Node *u){
    To_pushdown(o);
    while(o->fa!=u){
        if(o->fa->fa!=u){
            if(o->dir()==o->fa->dir())  Rotate(o->fa->fa,o->dir()^1);
        }
        Rotate(o->fa,o->dir()^1);
    }
    if(u==null)     root=o;
}
Node *Kth(Node *o,int k){
    o->pushdown();
    if(o->ch[0]->siz+1==k)      return o;
    if(k<=o->ch[0]->siz)    return Kth(o->ch[0],k);
    return Kth(o->ch[1],k-o->ch[0]->siz-1);
}
inline void Reverse(int l,int r){
    Node *x=Kth(root,l),*y=Kth(root,r+2);
    Splay(x,null);Splay(y,x);
    y->ch[0]->rev();
}
int main(){
    scanf("%d",&n);
    for(int i=2;i<=n+1;++i) scanf("%d",&a[i].x),a[i].id=i;
    sort(a+2,a+n+2,cmp);
    for(int i=2;i<=n+1;++i) a[i].rnk=i-1;
    sort(a+2,a+n+2,cmp_id);
    buildtree(null,root,1,n+2);
    for(int i=1;i<=n;++i){
        Splay(Find[i],null);
        int Rank=root->ch[0]->siz;
        if(i!=n)printf("%d ",Rank);
        else    printf("%d",Rank);
        Reverse(i,Rank);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zP1nG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值