51Nod1364 最大字典序排列

题目看这里

一道比较简单的贪心题

容易想到从前到后确定每一位

我们可以用一个splay来维护当前未确定的部分的顺序

假设当前剩下k次操作机会

那么我们可以求出splay中前k+1个元素中的最大元素i,令k减少rank(i),让后将其输出并从splay中删掉

最后k=0时,输出splay中剩余元素

比题解那个线段树好写多了,主要是不用想,而且splay还挺快的

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 100010
#define son(x) (s[f[x]][1]==x)
using namespace std;
int f[N],s[N][2],sz[N],l[N],t[N];
int n,k,cnt=0,rt=0;
inline int ps(int x){
    sz[x]=sz[s[x][0]]+sz[s[x][1]]+1;
    t[x]=max(l[x],max(t[s[x][0]],t[s[x][1]]));
}
inline void rot(int x){
    int p=f[x],g=f[p],d=son(x);
    s[p][d]=s[x][!d]; f[s[p][d]]=p;
    s[x][!d]=p; f[p]=x; f[x]=g;
    if(g) s[g][p==s[g][1]]=x; ps(p); ps(x);
}
inline void splay(int x,int r=0){
    for(int p;(p=f[x])!=r;rot(x))
        if(f[p]!=r && son(x)==son(p)) rot(p);
    if(!r) rt=x;
}
inline int select(int k,int x=rt){
    for(int w;;){
        w=sz[s[x][0]]+1;
        if(w==k) return x;
        if(k<w) x=s[x][0];
        else k-=w,x=s[x][1];
    }
}
inline int rank(int x){
    int r=sz[s[x][0]]+1;
    for(;x;x=f[x])
        if(son(x)) r+=sz[s[f[x]][0]]+1;
    return r;
}
inline int merge(int x,int y){
    if(x&&y){
        y=select(1,y);
        splay(y,rt);
        s[y][0]=x; f[x]=y; ps(y);
        return y;
    } return x+y;
}
inline int fMax(int x){
    for(;;){
        if(l[x]==t[x]) return x;
        else if(t[s[x][0]]>t[s[x][1]]) x=s[x][0]; else x=s[x][1];
    }
}
int main(){
    scanf("%d%d",&n,&k);
    for(int x,i=1;i<=n;++i){
        scanf("%d",l+i);
        if(i>1){ f[i-1]=i; s[i][0]=i-1; ps(i); } else sz[i]=1,ps(i);
    }
    rt=n;
    for(int i=1,j;k>0&&i<=n;++i){
        splay(select(min(k+1,sz[rt])));
        if(l[rt]>t[s[rt][0]]) j=rt;
        else splay(fMax(s[rt][0]));
        printf("%d
",l[rt]); k-=sz[s[rt][0]]; rt=merge(s[rt][0],s[rt][1]); f[rt]=0;
    }
    while(sz[rt]) splay(select(1)),printf("%d
",l[rt]),rt=merge(s[rt][0],s[rt][1]),f[rt]=0;;
}

原文地址:https://www.cnblogs.com/Extended-Ash/p/9477087.html