P3165 [CQOI2014] 排序机械臂

题意

有一个序列 \(P=p_1,p_2,\dots,p_n\),第一次找出最小值的位置 \(a_1\),翻转 \([1,a_1]\),第二次找到次小值得位置 \(a_2\),反转 \([2,a_2]\),以此类推。要求输出 \(a_1,a_2,\dots,a_n\)
\(n\le10^5,p_i\le10^7\)

思路

直接按照题意模拟即可,用 \(Splay\) 维护序列。

代码

// Problem: P3165 [CQOI2014] 排序机械臂
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3165
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T&x){
        x=0;char c=getchar();bool f=0;
        while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
        while(isdigit(c)) x=x*10+c-'0',c=getchar();
        f?x=-x:0;
    }
    template<typename T>
    inline void write(T x){
        if(x==0){putchar('0');return ;}
        x<0?x=-x,putchar('-'):0;short st[50],top=0;
        while(x) st[++top]=x%10,x/=10;
        while(top) putchar(st[top--]+'0');
    }
    inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
    inline void write(char c){putchar(c);}
    inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
    inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
    template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
    template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
    template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
const int maxn=100010,inf=1000000000;
int n,a[maxn],wz[maxn];
struct PX{
    int val,id;
    bool operator<(const PX t)const{
        if(val!=t.val) return val<t.val;
        return id<t.id;
    }
}p[maxn];
class Splay{
private:
    struct node{
        int ch[2],rev,fa,sz;
        node(){sz=1;}
    }t[maxn];
    vector<int>path;
    int get(int u){return t[t[u].fa].ch[1]==u;}
    void push_up(int u){t[u].sz=t[t[u].ch[0]].sz+t[t[u].ch[1]].sz+1;}
    void reverse(int u){t[u].rev^=1,swap(t[u].ch[0],t[u].ch[1]);}
    void down(int u){
        if(!t[u].rev) return ;
        if(t[u].ch[0]) reverse(t[u].ch[0]);
        if(t[u].ch[1]) reverse(t[u].ch[1]);
        t[u].rev=0;
    }
    void rotate(int u){
        int fa=t[u].fa,faa=t[fa].fa;
        int d=get(u),dd=get(fa);
        if(faa) t[faa].ch[dd]=u;t[u].fa=faa;
        t[fa].ch[d]=t[u].ch[!d];if(t[u].ch[!d]) t[t[u].ch[!d]].fa=fa;
        t[u].ch[!d]=fa,t[fa].fa=u;
        push_up(fa),push_up(u);
    }
    void splay(int u,int mb=0){
        int uu=u;
        while(uu!=mb) path.push_back(uu),uu=t[uu].fa;
        path.push_back(uu);
        while(!path.empty()) down(path.back()),path.pop_back();
        for(;t[u].fa!=mb;rotate(u)) if(t[t[u].fa].fa!=mb) rotate(get(u)==get(t[u].fa)?t[u].fa:u);
    }
    int get_rank(int u){splay(u);return t[t[u].ch[0]].sz;}
    int kth(int u,int k){
        while(u){
            down(u);
            if(t[t[u].ch[0]].sz>=k) u=t[u].ch[0];
            else if(t[t[u].ch[0]].sz+1==k) return u;
            else k-=t[t[u].ch[0]].sz+1,u=t[u].ch[1];
        }
        return -1;
    }
public:
    void init(){
        t[0].sz=0;
        for(int i=1;i<=n;i++) read(p[i].val),p[i].id=i;
        sort(p+1,p+1+n);
        for(int i=1;i<=n;i++) wz[i]=p[i].id+1;
        for(int i=2;i<=n+1;i++){
            t[i].fa=i-1;
            t[i-1].ch[1]=i;
        }
        t[n+2].fa=n+1,t[n+1].ch[1]=n+2;
        for(int i=n+2;i>=1;i--) push_up(i);
    }
    void work(){
        for(int i=1;i<=n;i++){
            int ans;
            write(ans=get_rank(wz[i])),write(" ");
            int L=kth(wz[i],i),R=kth(wz[i],ans+2);
            splay(L),splay(R,L);
            reverse(t[R].ch[0]);
        }
    }
}t;
signed main(){
    read(n);
    t.init();
    t.work();
    return 0;
}
posted @ 2026-05-22 22:06  Link-Cut_Trees  阅读(7)  评论(0)    收藏  举报