[CQOI2014]排序机械臂

 

P3165 [CQOI2014]排序机械臂

题目描述

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

样例说明

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

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

输入输出格式

输入格式:

第一行包含正整数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

首先明白一个事,这个题主体是在让你干什么。这个题明显,要维护一个数据结构,让这个数据结构实现区间翻转和 查询工作。

区间翻转应该都会了吧。不会的请左转去文艺平衡树那个模板题。我这里主要介绍一下建树的操作和查询。

可以发现,那个模板题建树的时候数字是完全有序的,所以可以直接建树。这个题由于给了一个高度,所以不能这么干,然而我们可以使用结构体,以高度为第一关键字,下标为第二关键字sort一下,然后高度就没用了,我们执行模板里的翻转操作即可。

然后我们要求的是什么,一个排名,没错。那么想一下,如果我们把要求的那个点直接旋转到根节点,然后求出它的左子树大小+1是不是就可以了,省去了很多功夫。然而要注意的是,我们因为一开始设置了哨兵节点,所以最后还要-1.

剩下的就没什么很困难的了,不明白的再仔细看看代码吧。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define re register
#define maxn 1000007
#define ll long long
#define ls rt<<1
#define rs rt<<1|1
#define inf 1000000007
using namespace std;
int ch[100001][2],f[maxn],cnt[maxn],key[maxn],size[maxn],mark[maxn],root,sz,data[maxn];
struct po
{
    int id,k;
}a[maxn];
inline int read()
{
    int x=0,c=1;
    char ch=' ';
    while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
    while(ch=='-')c*=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();
    return x*c;
}
bool cmp(po x,po y)
{
    if(x.k<y.k)
    return 1;
    else if(x.k==y.k)
    return x.id<y.id;
    return 0;
}
inline int get(int x)
{
    return ch[f[x]][1]==x;
}
inline void update(int x)
{
    size[x]=size[ch[x][1]]+size[ch[x][0]]+1;
}
inline void pushdown(int x)
{
    if(mark[x]){
        if(ch[x][0]) mark[ch[x][0]]^=1;
        if(ch[x][1]) mark[ch[x][1]]^=1;
        swap(ch[x][0],ch[x][1]);
        mark[x]=0;
    }
}
inline void rotate(int x)
{
    int y=f[x],z=f[y];
    int kind=get(x);
    pushdown(y);pushdown(x);
    ch[y][kind]=ch[x][kind^1];f[ch[y][kind]]=y;
    ch[x][kind^1]=y;f[y]=x;f[x]=z;
    if(z){
        ch[z][ch[z][1]==y]=x;
    }
    update(y);update(x);
}
inline void splay(int x,int tar)
{
    for(re int fa;(fa=f[x])!=tar;rotate(x)){
        pushdown(f[fa]);pushdown(fa);pushdown(x);
        if(f[fa]!=tar)
            rotate(get(x)==get(fa)?fa:x);
    }
    if(!tar) root=x;
}
inline void build(int l,int r,int fa)
{
   if(l>r) return;
    int mid=l+r>>1;
    if(mid<fa) ch[fa][0]=mid;
    else ch[fa][1]=mid;
    size[mid]=1;f[mid]=fa;
    if(l==r) return;
    build(l,mid-1,mid);
    build(mid+1,r,mid);
    update(mid);
}
inline int findx(int x)
{
    int now=root;
    while(1){
        if(mark[now])
        pushdown(now);
        if(x<=size[ch[now][0]]&&ch[now][0])
        now=ch[now][0];
        else {
            x-=size[ch[now][0]]+1;
            if(x==0) return now;
            else now=ch[now][1];
        }
    }
}
int main()
{
    int n;
    cin>>n;
    for(re int i=2;i<=n+1;i++){
        a[i].k=read();
        a[i].id=i;
    }
    a[1].id=1,a[1].k=-inf;
    a[n+2].id=n+2,a[n+2].k=inf;
    sort(a+1,a+n+3,cmp);
    build(1,n+2,0);
    root=n+3>>1;
    for(re int i=2;i<=n;i++){
        splay(a[i].id,0);
        int ans=size[ch[root][0]]+1;
        printf("%d ",ans-1);
        int x1=findx(i-1);
        int y1=findx(ans+1);
        splay(x1,0);splay(y1,x1);
        mark[ch[ch[root][1]][0]]^=1;
    }
    cout<<n;
}
原文地址:https://www.cnblogs.com/victorique/p/8682401.html