洛谷P3165 [CQOI2014]排序机械臂

题目描述

为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂。它遵循一个简单的排序规则,第一次操作找到高度最低的物品的位置 P_1P1 ,并把左起第一个物品至 P_1P1 间的物品 (即区间 [1,P_1][1,P1] 间的物品) 反序;第二次找到第二低的物品的位置 P_2P2 ,并把左起第二个至 P_2P2 间的物品 (即区间 [2,P_2][2,P2] 间的物品) 反序……最终所有的物品都会被排好序。

样例说明

上图给出有六个物品的示例,第一次操作前,高度最低的物品在位置 44 ,于是把第一至第四的物品反序;第二次操作前,第二低的物品在位罝六,于是把第二至六的物品反序……

你的任务便是编写一个程序,确定一个操作序列,即每次操作前第 ii 低的物品所在位置 P_iPi ,以便机械臂工作。需要注意的是,如果有高度相同的物品,必须保证排序后它们的相对位置关系与初始时相同。

输入输出格式

输入格式:

第一行包含正整数n,表示需要排序的物品数星。

第二行包含n个空格分隔的整数ai,表示每个物品的高度。

输出格式:

输出一行包含n个空格分隔的整数Pi。

输入输出样例

输入样例#1: 
6
3 4 5 1 6 2
输出样例#1: 
4 6 4 5 6 6

说明

N<=100000

Pi<=10^7

区间翻转+区间kth

二话不说splay!

(如果你真的要用 treap 我也不阻止。。。)

但是高度是无序的,而splay是有序的,怎么办呢?

所以,用结构体存 高度 与 下标,排一遍序,高度就可以丢一边了。。。

具体看代码中的 splay::reserve 。

注意

1. 头尾设两个哨兵节点。

2. splay 每次都要pushdown一次(巨坑)!

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 100010
#define MAX 999999999
using namespace std;
int n,size=1,root=0;
struct node{
    int x,id;
}b[MAXN];
namespace splay{
    struct Splay{
        int f,s,flag,son[2];
        int v;
    }a[MAXN];
    inline void clean(int rt){
        a[rt].son[0]=a[rt].son[1]=a[rt].f=a[rt].s=a[rt].flag=a[rt].v=0;
    }
    inline void pushup(int rt){
        if(!rt)return;
        a[rt].s=a[a[rt].son[0]].s+a[a[rt].son[1]].s+1;
    }
    inline void pushdown(int rt){
        if(!rt||!a[rt].flag)return;
        a[a[rt].son[0]].flag^=1;a[a[rt].son[1]].flag^=1;a[rt].flag^=1;
        swap(a[rt].son[0],a[rt].son[1]);
    }
    inline void turn(int rt,int k){
        int x=a[rt].f,y=a[x].f;
        a[x].son[k^1]=a[rt].son[k];
        if(a[rt].son[k])a[a[rt].son[k]].f=x;
        a[rt].f=y;
        if(y)a[y].son[a[y].son[1]==x]=rt;
        a[x].f=rt;
        a[rt].son[k]=x;
        pushup(x);pushup(rt);
    }
    void splay(int rt,int ancestry){
        while(a[rt].f!=ancestry){
            int x=a[rt].f,y=a[x].f;
            pushdown(y);pushdown(x);pushdown(rt);
            if(y==ancestry)turn(rt,a[x].son[0]==rt);
            else{
                int k=a[y].son[0]==x?1:0;
                if(a[x].son[k]==rt){turn(rt,k^1);turn(rt,k);}
                else{turn(x,k);turn(rt,k);}
            }
        }
        if(ancestry==0)root=rt;
    }
    inline int newnode(int x){
        int rt=size++;
        clean(rt);
        a[rt].v=x;a[rt].s=1;
        return rt;
    }
    int buildtree(int l,int r){
        if(l>r)return 0;
        int mid=l+r>>1,lson=0,rson=0;
        lson=buildtree(l,mid-1);
        int rt=newnode(b[mid].x);
        rson=buildtree(mid+1,r);
        a[rt].son[0]=lson;
        a[rt].son[1]=rson;
        if(lson)a[lson].f=rt;
        if(rson)a[rson].f=rt;
        pushup(rt);
        return rt;
    }
    int kth(int rt,int k){
        if(a[rt].s<k)return 0;
        while(1){
            pushdown(rt);
            int y=a[rt].son[0];
            if(k>a[y].s+1){
                k-=a[y].s+1;
                rt=a[rt].son[1];
            }
            else if(k<=a[y].s)rt=y;
            else return rt;
        }
    }
    inline void reverge(int i){
        splay(b[i].id+1,0);
        int s=a[a[root].son[0]].s;
        printf("%d ",s);
        int front=kth(root,i),next=kth(root,s+2);
        splay(front,0);splay(next,front);
        a[a[next].son[0]].flag^=1;
    }
}
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
bool cmp(const node &x,const node &y){
    if(x.x==y.x)return x.id<y.id;
    return x.x<y.x;
}
void init(){
    n=read();
    for(int i=1;i<=n;i++){
        b[i].x=read();
        b[i].id=i;
    }
    b[0].x=-MAX;b[0].id=1;
    b[n+1].x=MAX;b[n+1].id=n+1;
    sort(b+1,b+n+1,cmp);
    root=splay::buildtree(0,n+1);
    for(int i=1;i<=n-1;i++)splay::reverge(i);
    printf("%d\n",n);
}
int main(){
    init();
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值