题目链接:http://codeforces.com/problemset/problem/1023/D
之前想的时候忘了如果序列中没有q,也没有0时应该输出no
先特判,若果没有q并且有0,则先任意将一个0置为q,然后将所有的0置为他们相邻的值。这样不会影响序列的合法性,并且序列中没有了0,只需判断是否合法即可
用线段树查询一个数字出现的两个端点之间是否有比它小的数,如果有输出no,如果每个数都没有输出yes
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define mod 1000000007
#define For(i,m,n) for(int i=m;i<=n;i++)
#define Dor(i,m,n) for(int i=m;i>=n;i--)
#define LL long long
#define lan(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=200010;
struct node
{
int l,r;
int m;//存储值
};
node tree[N*4];
int a[N],b[N],c[N];
void build(int n ,int l,int r)
{
tree[n].l=l;
tree[n].r=r;
if(l==r)
{
tree[n].m=a[l];//视情况
return;
}
int mid=(l+r)>>1;
build(n*2,l,mid);
build(n*2+1,mid+1,r);
tree[n].m=min(tree[n*2].m,tree[n*2+1].m);/看线段树种类
}
int query(int n,int l,int r)
{
if(l>r)
return -1;
if(tree[n].l==l&&tree[n].r==r)
{
return tree[n].m;
}
int mid=(tree[n].r+tree[n].l)/2;
int res=0;
if(r<=mid)
res=query(n*2,l,r);
else if(l>=mid+1)
res=query(n*2+1,l,r);
else
{
res=query(n*2,l,mid);看线段树种类
res=min(res,query(n*2+1,mid+1,r));看线段树种类
}
return res;
}
int n,q;
int f=0;
bool pin()
{
For(i,1,q)
{
if(b[i]!=inf)
{
if(query(1,b[i],c[i])<i)
return false;
}
}
printf("YES\n");
For(i,1,n)
if(i==n)
printf("%d\n",a[i]);
else
printf("%d ",a[i]);
return true;
}
int main()
{
while(~scanf("%d%d",&n,&q))
{
lan(b,inf);
lan(c,0);
lan(tree,0);
lan(a,0);
f=0;
int maxx=-1;
For(i,1,n)
{
scanf("%d",&a[i]);
if(a[i]==0)f++;
else
{
b[a[i]]=min(i,b[a[i]]);
c[a[i]]=max(i,c[a[i]]);
}
maxx=max(maxx,a[i]);
}
if(f==n)
{
printf("YES\n");
For(i,1,n)
if(i==n)
printf("%d\n",q);
else
printf("%d ",q);
continue;
}
if(maxx!=q&&f==0)
{
printf("NO\n");
continue;
}
else if(maxx!=q&&f!=0)
{
For(i,1,n)
if(!a[i]){a[i]=q;break;}
}
For(i,1,n)
if(!a[i])a[i]=a[i-1];
Dor(i,n,1)
if(!a[i])a[i]=a[i+1];
build(1,1,n);
if(pin()==false)
printf("NO\n");
}
return 0;
}