CF1023D Array Restoration


不合法的情况只有两种


  1. aba,其中a>b
  2. 序列中没有0,没有m

第一种可直接无脑主席树判断,也可以和下面一样用set

考虑填数,对于 i 位置,\(a_i=0\),若 i 左右两边存在相等的数,设为w,i 位置填\(\max(w)\),否则置为 1

这种填数方案保证当前位置合法,并且不会对其他位置造成新的影响

维护这个\(\max(w)\),可以在w第一次出现时加入set,最后一次出现时删掉,每次取\(* rbegin()\)即可

#include<set>
#include<cstdio>
#include<iostream>
using namespace std;
const int N=2e5+11;
struct tree{
int lc,rc;
int sum;
}tre[20*N];
int tot=1;
int n,q;
int a[N];
int l[N],r[N];
int root[N];
set<int> st;
inline int read()
{
int s=0;
char ch=getchar();
while(ch>'9'||ch<'0') ch=getchar();
while(ch>='0'&&ch<='9')
{
s=(s<<1)+(s<<3)+(ch^48);
ch=getchar();
}
return s;
}
inline int min_(int x,int y){return x>y?y:x;}
inline int max_(int x,int y){return x>y?x:y;}
void insert(int &i,int j,int l,int r,int x)
{
if(!i) i=++tot;
tre[i].lc=tre[j].lc;
tre[i].rc=tre[j].rc;
tre[i].sum=tre[j].sum+1;
if(l==r) return;
int mid=(l+r)>>1;
if(x<=mid) insert(tre[i].lc=0,tre[j].lc,l,mid,x);
else insert(tre[i].rc=0,tre[j].rc,mid+1,r,x);
return;
}
int query(int i,int j,int l,int r,int L,int R)
{
if(l>=L&&r<=R) return tre[j].sum-tre[i].sum;
int mid=(l+r)>>1;
int ans=0;
if(L<=mid) ans=query(tre[i].lc,tre[j].lc,l,mid,L,R);
if(R>mid) ans+=query(tre[i].rc,tre[j].rc,mid+1,r,L,R);
return ans;
}
int main()
{
n=read();
q=read();
for(int i=1;i<=n;++i) a[i]=read();
root[0]=1;
int maxx=0,sum=0;
for(int i=1;i<=n;++i)
{
if(a[i]==0){++sum;root[i]=root[i-1];continue;}
insert(root[i],root[i-1],1,q,a[i]);
if(!l[a[i]]) l[a[i]]=r[a[i]]=i;
else r[a[i]]=i;
maxx=max_(maxx,a[i]);
}
if(sum==0&&maxx!=q){printf("%s\n","NO");return 0;}
for(int i=2;i<=maxx;++i)
{
if(l[i]==0) continue;
if(query(root[l[i]-1],root[r[i]],1,q,1,i-1)){printf("%s\n","NO");return 0;}
}
bool jd=0;
if(maxx!=q) jd=1;
for(int i=1;i<=n;++i)
{
if(jd){if(a[i]==0){a[i]=q;jd=0;continue;}}
if(a[i]==0){if(st.size()) a[i]=*st.rbegin();else a[i]=1;}
else{if(l[a[i]]==r[a[i]])continue;if(i==l[a[i]])st.insert(a[i]);else if(i==r[a[i]])st.erase(st.find(a[i]));}
}
cout<<"YES"<<endl;
for(int i=1;i<=n;++i) printf("%d ",a[i]);
return 0;
}