一道比较简单的贪心题
容易想到从前到后确定每一位
我们可以用一个splay来维护当前未确定的部分的顺序
假设当前剩下k次操作机会
那么我们可以求出splay中前k+1个元素中的最大元素i,令k减少rank(i),让后将其输出并从splay中删掉
最后k=0时,输出splay中剩余元素
比题解那个线段树好写多了,主要是不用想,而且splay还挺快的
#include#include #include #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 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\n",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\n",l[rt]),rt=merge(s[rt][0],s[rt][1]),f[rt]=0;;}