AtCoder-arc227_b Know Your Place 题解
Solution
我们从小到大依次枚举值 \(x\) 并将所有 \(x\) 插入序列。初始时序列为空。
设当前值为 \(x\) 的数出现了 \(y\) 次。由于目前序列里所有数都 \(<x\),我们一定会在当前序列的第 \(x\) 位后插入 \(y\) 个 \(x\)。如果答案序列长度不够则一定无解。
模拟上述过程,用 FHQ Treap 维护答案序列即可。
Code
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i(a);i<b;++i)
#define ls(p) t[p].ls
#define rs(p) t[p].rs
using namespace std;
const int N=5e5+5;
int a[N],ans[N],rt,n,m,j,len,l,r;
struct Node{int ls,rs,pri,sz,ch;}t[N];
inline int nwnode(int c){
return t[++m]={0,0,rand(),1,c},m;
}
inline void pushup(int p){
t[p].sz=t[ls(p)].sz+t[rs(p)].sz+1;
}
void dfs(int p){
if(ls(p)) dfs(ls(p));
cout<<t[p].ch<<' ';
if(rs(p)) dfs(rs(p));
}
void split(int p,int x,int &l,int &r){
if(!p) return l=r=0,void();
if(t[ls(p)].sz+1<=x) l=p,split(rs(p),x-t[ls(p)].sz-1,rs(p),r);
else r=p,split(ls(p),x,l,ls(p));
pushup(p);
}
int merge(int l,int r){
if(!l||!r) return l|r;
if(t[l].pri<t[r].pri) return rs(l)=merge(rs(l),r),pushup(l),l;
else return ls(r)=merge(l,ls(r)),pushup(r),r;
}
signed main(){
cin.tie(0)->sync_with_stdio(0);
cin>>n;
rep(i,0,n) cin>>a[i];
sort(a,a+n);
a[n++]=N;
rep(i,1,n){
if(a[i]^a[j]){
// 值为a[j]出现了i-j次
if(len<a[j]) return cout<<"No",0;
int l,r;
split(rt,a[j],l,r);
rep(_,0,i-j) l=merge(l,nwnode(a[j]));
rt=merge(l,r);
len+=i-j;
j=i;
}
}
cout<<"Yes\n";
dfs(rt);
return 0;
}

浙公网安备 33010602011771号