HDU 1890 Robotic Sort 单点查找区间翻转 Splay裸题

博客详细介绍了HDU 1890题目,即如何通过查找序列中靠右的最大值Maxval,并对其所在位置x进行区间翻转来实现排序。在n次这样的操作后,序列将被排序。当Maxval等于x时,虽然看似无效,但仍然需要执行翻转操作。
摘要由CSDN通过智能技术生成

题意:给定n长的序列

找到其中靠右的最大值 Maxval 所在的位置 x

把[Maxval, x] 翻转一下。

如此进行n次排序(若Maxval==x, 则翻转[x,x] 区间(就是类似于无效操作,但是要进行)


#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<set>
#include<queue>
using namespace std;

#define L(x) tree[x].ch[0]
#define R(x) tree[x].ch[1]
#define Father(x) tree[x].fa
#define Size(x) tree[x].size
#define Val(x) tree[x].val
#define Minv(x) tree[x].minv
#define Filp(x) tree[x].filp
#define ll int
#define inf 10000000
#define N 200005
inline ll Mid(ll x,ll y){return (x+y)>>1;}
struct node{
    int ch[2], fa, size;
    int val, minv, filp;
}tree[N];
int tot, root;
struct A{
    int val, pos;
    bool operator<(const A& a)const{
        return (val==a.val&&pos<a.pos)||(val<a.val);  
    }  
}a[N];
int n;
node Newnode(int val, int fa, int size){
    node E={0,0,fa,size, val, val, 0};
    return E;
}
void push_up(int id){
    Size(id) = Size(L(id))+Size(R(id))+1;    
    Minv(id) = min(Minv(L(id)), Minv(R(id)));
    Minv(id) = min(Val(id), Minv(id));
}
void push_down(int id){
    if(Filp(id))
    {
        Filp(id) = 0;
        Filp(L(id))^=1;
        Filp(R(id))^=1;
        swap(L(id),R(id));
    }
}
void rotate(ll id, ll kind){ //kind为0代表左旋 为1代表右旋
    ll y = Father(id);
    push_down(id); push_down(y);
    Father(tree[id].ch[kind]) = y;
    tree[y].ch[kind^1] = tree[id].ch[kind];
    if(Father(y))
        tree[Father(y)].ch[ R(Father(y))==y ] = id;
    Father(id) = Father(y);
    tree[id].ch[kind] = y;
    Father(y) = id;
    push_up(y);
}
void splay(ll id, ll goal){
    push_down(id);
    while(Father(id)!=goal){
        if(Father( Father(id) ) == goal)
            rotate(id, L(Father(id)) == id);
        else
        {
            ll y = Father(id);
            ll kind = L(Father(y)) == y;
            if(tree[y].ch[kind] == id) //共线
            {
                rotate(id, kind^1);
                rotate(id, kind);
            }
            else
            {
                rotate(y, kind);
                rotate(id,kind);
            }
        }
    }
    push_up(id);
    if(goal == 0)root = id;
}
void RotateTo(ll k, ll goal){ //把第k个节点伸展到goal下
    ll id = root;
    push_down(id);
    while(Size(L(id))!=k){
        if(Size(L(id)) > k)
            id = L(id);
        else {
            k -= (Size(L(id))+1);
            id = R(id);
        }
        push_down(id);
    }
    splay(id, goal);
}
void Interval(ll l, ll r){
    RotateTo(l, 0);
    RotateTo(r, root);
}
ll find_min(ll v){
    ll id = root;
    push_down(id);
    while(Val(id)!=v){
        id =( (Minv(L(id))==v)?L(id):R(id) );
        push_down(id);
    }
    return id;
}
ll D[N];
int build(ll l, ll r, ll fa){
    if(l>r)return 0;
    ll mid = Mid(l,r);
    ll id = tot;
    tree[tot++] = Newnode(D[mid], fa, 1);
    L(id) = build(l, mid-1, id);
    R(id) = build(mid+1, r, id);
    push_up(id);
    return id;
}
void init(){
    tree[0] = Newnode(inf,0,0);
    tot = root = 1;
    tree[tot++] = Newnode(inf,0,1);
    tree[tot++] = Newnode(inf,R(root),1);
    R(root) = tot-1;
    L(R(root)) = build(1,n,R(root));
    push_up(R(root));
    push_up(root);
}
ll getmax(ll id){//找到id这个子树下的最大值的标号
    push_down(id);
    while(R(id)){
        id = R(id);
        push_down(id);
    }
    return id;
}
void Delroot(){
    if(L(root)==0){
        root = R(root);
        Father(root) = 0;
        return;
    }
    int now = getmax(L(root));
    splay(now, root);
    int id = root;
    root = now;
    Father(root) = 0;
    R(root) = R(id);
    Father(R(id)) = root;
    push_up(root);
}
int main(){
    ll i, j, u ,v;
    while(scanf("%d",&n),n){
        for(i=1;i<=n;i++)scanf("%d",&a[i].val), a[i].pos = i;
        sort(a+1,a+n+1);
        for(i=1;i<=n;i++)D[a[i].pos] = i;
        init();
        for(i=1;i<=n;i++){
            splay(find_min(i),0);
            printf("%d", Size(L(root))+i);
            Filp(L(root))^=1;            
            Delroot();
            i==n?puts(""):printf(" ");
        }
    }
    return 0;
}





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值