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;
}
posted @ 2026-08-19 13:15  xiaoniu142857  阅读(10)  评论(0)    收藏  举报