HDU 1890. Robotic Sort

链接

http://acm.hdu.edu.cn/showproblem.php?pid=1890

题意

对于序列中第 i i i 大的数,其在序列中位置为 p o s i pos_i posi,翻转区间 [ i , p o s i ] [i,pos_i] [i,posi],最终使序列升序排列。

对于一样大的数,在初始序列中下标较小的定义为较小的那一个。

思路

用 Splay 树维护区间翻转,先对下标建树。

对于翻转操作,记当前要翻转第 i i i 大的数,将 i i i 上旋至树根,给左子树打上翻转标记,然后将树根删除。

注意下传翻转标记。

代码

#include <bits/stdc++.h>
#define SZ(x) (int)(x).size()
#define ALL(x) (x).begin(),(x).end()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define FI first
#define SE second
using namespace std;
typedef double DB;
typedef long double LD;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<PII> VPII;
// head
const int N=1e5+5;
int n;
PII a[N];
struct Splay {
    int rt,ch[N][2],sz[N],fa[N],mark[N];
    PII val[N];
    bool get(int x) {return x==ch[fa[x]][1];}
    void clear(int x) {ch[x][0]=ch[x][1]=fa[x]=mark[x]=sz[x]=0;}
    void push_up(int x) {sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;}
    void push_down(int x) {
        if(mark[x]) {
            mark[ch[x][0]]^=1;
            mark[ch[x][1]]^=1;
            mark[x]=0;
            swap(ch[x][0],ch[x][1]);
        }
    }
    void build(int l,int r,int f) {
        int mid=l+r>>1;
        val[mid]=a[mid];
        if(f==-1) rt=mid;
        else fa[mid]=f,ch[f][r>f]=mid,ch[mid][0]=ch[mid][1]=0;
        if(l<mid) build(l,mid-1,mid);
        if(r>mid) build(mid+1,r,mid);
        push_up(mid);
    }
    void rotate(int x) {
        int y=fa[x],z=fa[y];
        push_down(y);
        push_down(x);
        int chk=get(x);
        ch[y][chk]=ch[x][chk^1];
        if(ch[x][chk^1]) fa[ch[x][chk^1]]=y;
        ch[x][chk^1]=y;
        fa[y]=x,fa[x]=z;
        if(z) ch[z][y==ch[z][1]]=x;
        push_up(y);
    }
    void splay(int x) {
        push_down(x);
        for(int f=fa[x];f=fa[x],f;rotate(x)) if(fa[f])
            rotate(get(x)==get(f)?f:x);
        push_up(x);
        rt=x;
    }
    int pre() {
        int cur=ch[rt][0];
        push_down(cur);
        while(ch[cur][1]) cur=ch[cur][1],push_down(cur);
        splay(cur);
        return cur;
    }
    void del() {
        if(!ch[rt][0]&&!ch[rt][1]) {
            clear(rt);
            rt=0;
            return;
        }
        else if(!ch[rt][0]) {
            int cur=rt;
            rt=ch[rt][1];
            fa[rt]=0;
            clear(cur);
        }
        else if(!ch[rt][1]) {
            int cur=rt;
            rt=ch[rt][0];
            fa[rt]=0;
            clear(cur);
        }
        else {
            int cur=rt;
            pre();
            fa[ch[cur][1]]=rt;
            ch[rt][1]=ch[cur][1];
            clear(cur);
            push_up(rt);
        }
    }
    void reverse(int x,int t) {
        splay(x);
        mark[ch[rt][0]]^=1;
        printf("%d%c",sz[ch[rt][0]]+t,t==n?'\n':' ');
        del();
    }
}splay;
bool cmp(PII a,PII b) {
    return a.SE<b.SE||a.SE==b.SE&&a.FI<b.FI;
}
int main() {
    while(~scanf("%d",&n)&&n) {
        for(int i=1;i<=n;i++) {
            int x;
            cin>>x;
            a[i]=MP(i,x);
        }
        splay.build(1,n,-1);
        sort(a+1,a+1+n,cmp);
        for(int i=1;i<=n;i++) splay.reverse(a[i].FI,i);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值