1. 程式人生 > >洛谷P3165 [CQOI2014]排序機械臂【splay】

洛谷P3165 [CQOI2014]排序機械臂【splay】

物體 題目 分享圖片 char s node 如果 反序 splay upd

題目描述
為了把工廠中高低不等的物品按從低到高排好序,工程師發明了一種排序機械臂。它遵循一個簡單的排序規則,第一次操作找到高度最低的物品的位置 $p_1$,並把左起第一個物品至$p_1$間的物品 (即區間 $[1,p_1]$間的物品) 反序;第二次找到第二低的物品的位置$p_2$,並把左起第二個至$p_2$ 間的物品 (即區間$[2,p_2]$間的物品) 反序……最終所有的物品都會被排好序。
技術分享圖片

上圖給出有六個物品的示例,第一次操作前,高度最低的物品在位置 4 ,於是把第一至第四的物品反序;第二次操作前,第二低的物品在位罝六,於是把第二至六的物品反序……

你的任務便是編寫一個程序,確定一個操作序列,即每次操作前第$p_i$ 低的物品所在位置$p_i$,以便機械臂工作。需要註意的是,如果有高度相同的物品,必須保證排序後它們的相對位置關系與初始時相同。

輸入格式:

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

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

輸出格式:

輸出一行包含n個空格分隔的整數Pi。

輸入樣例

6
3 4 5 1 6 2

輸出樣例

4 6 4 5 6 6

說明

N<=100000
Pi<=10^7
************************

題目分析

比較常規的splay區間翻轉題
加入哨兵結點建樹
高度排序後一次查詢排名並翻轉

有兩點需要註意
1.每次要先把元素旋轉到根得到他的排名在反轉區間
所以在這裏splay裏面也要加push下推
而且 z, y, x都要push

2.高度相同的物體排序後順序也要相同
讀入時要把高度與編號存入結構體再雙關鍵字排序


若直接對高度sort,可能存在不穩定性
手寫sort請無視


#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;

int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<‘0‘||ss>‘9‘){if(ss==‘-‘)f=-1;ss=getchar();}
    while(ss>=‘0‘&&ss<=‘9‘){x=x*10+ss-‘0‘;ss=getchar();}
    return f*x;
}

const int maxn=200010;
int n;
struct node{int v,pos;}a[maxn];
int ch[maxn][2],fa[maxn];
int size[maxn],sz,rt;
int lzy[maxn];

bool cmp(node a,node b)
{
    if(a.v==b.v) return a.pos<b.pos;
    return a.v<b.v;
}

void update(int p)
{
    size[p]=size[ch[p][0]]+size[ch[p][1]]+1;
}

inline void push(int p)
{
    if(lzy[p])
    {
        swap(ch[p][0],ch[p][1]);
        lzy[ch[p][0]]^=1; lzy[ch[p][1]]^=1;
        lzy[p]=0;
    }
}

void rotate(int &p,int x)
{
    int y=fa[x],z=fa[y];
    int t=(ch[y][0]==x);
    if(y==p) p=x;
    else if(ch[z][0]==y) ch[z][0]=x;
    else ch[z][1]=x;
    fa[y]=x; fa[ch[x][t]]=y; fa[x]=z;
    ch[y][t^1]=ch[x][t]; ch[x][t]=y;
    update(y); update(x);
}

void splay(int &p,int x)
{
    while(x!=p)
    {
        int y=fa[x],z=fa[y];
        push(z);push(y);push(x);
        if(y!=p)
        {
            if((ch[z][0]==y)^(ch[y][0]==x))rotate(p,x);
            else rotate(p,y);
        }
        rotate(p,x);
    }
}

void build(int p,int ll,int rr)
{
    if(ll>rr) return;
    int mid=ll+rr>>1;
    fa[mid]=p; size[mid]=1;
    ch[p][mid>p]=mid;
    if(ll==rr) return;
    build(mid,ll,mid-1);build(mid,mid+1,rr);
    update(mid); 
}

int find(int p,int k) 
{ 
    push(p);  
    int ss=size[ch[p][0]]; 
    if(k==ss+1) return p;    
    if(k<=ss) return find(ch[p][0],k);
    else return find(ch[p][1],k-ss-1);  
}  

void rev(int ll,int rr)
{
    int x=find(rt,ll-1),y=find(rt,rr+1);
    splay(rt,x);
    splay(ch[rt][1],y); 
    lzy[ch[y][0]]^=1;
}

void solve()
{
    for(int i=2;i<=n;++i)
    {
        int x=a[i].pos; 
        splay(rt,x);
        printf("%d ",size[ch[rt][0]]);
        int ll=i-1,rr=size[ch[rt][0]];
        rev(ll+1,rr+1);
    }
    printf("%d ",n);//最後一個元素的排名必定為n,所以不用查詢
}

int main()
{
    n=read(); 
    for(int i=2;i<=n+1;++i){ a[i].v=read(); a[i].pos=i;}
    a[1].v=-1e8; a[1].pos=1;//讀入高度信息
    a[n+2].v=1e8; a[n+2].pos=n+2;
    
    rt=n+3>>1;
    build(rt,1,n+2);
    
    sort(a+1,a+n+3,cmp);//雙關鍵字排序
    solve();
    return 0;
}

洛谷P3165 [CQOI2014]排序機械臂【splay】