D. Array Restoration
http://codeforces.com/contest/1023/problem/D
题意:给你一个有n个整数的数组,q次操作,第i次操作选择一个区间(不能为空)把这个区间里面的数都变成i(i>.=1&&i<=q),现在把这个变化过的数组中的一些数字变成0,问你能不能得到变成0之间的序列。如果序列可以恢复输出yes并且打印出这个序列,否则输出no
思路:通过分析我们可以判断序列无法恢复的情况,因为大的数字可以覆盖晓得数字,我们可以找到每个数字出现的区间,如果在这个区间里面有比他更小的数字,那么这个数字是无法恢复的,输出no。下面我们就开始恢复这个序列,我们从q开始恢复,如果q在变化后的序列总如果没有出现过,我们就要找到一个0,并用q代替这个0的位置,如果序列中没有0,那么这个序列是无法恢复的,因为每次选的区间不能为空,并且q是最后进行的操作,没有其他数字可以覆盖他,下面我们从小到大判断判断每个数字出现的区间里面有没有比他更小的数字出现,如果有就输出no,如果区间里面有0就把这个区间范围内的0变成当前询问的数字。我们可以使用线段树进行区间查询最小值
#include <cstdio>
#include <cmath>
#include <cstring>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <typeinfo>
#include <fstream>
#include <map>
#include <stack>
using namespace std;
const int maxn=2e5+50;
int a[maxn];
int Left[maxn];
int Right[maxn];
int minn[maxn*4];
void PushUp(int rt)
{
minn[rt]=min(minn[rt*2],minn[rt*2+1]);
}
void Build(int l,int r,int rt)
{
if(l==r)
{
minn[rt]=a[l];
return ;
}
int mid=(l+r)/2;
Build(l,mid,rt*2);
Build(mid+1,r,rt*2+1);
PushUp(rt);
}
void update(int x,int l,int r,int rt)
{
if(l==r)
{
minn[rt]=x;
a[l]=x;
return ;
}
int mid=(l+r)/2;
if(minn[rt*2]==0)
{
update(x,l,mid,rt*2);
}
if(minn[rt*2+1]==0)
{
update(x,mid+1,r,rt*2+1);
}
PushUp(rt);
}
int query(int l,int r,int L,int R,int rt,int x)
{
if(l<=L&&r>=R)
{
if(minn[rt]==0)
{
update(x,L,R,rt);
}
return minn[rt];
}
int mid=(L+R)/2;
int ans=1e9;
if(mid>=l) ans=min(ans,query(l,r,L,mid,rt*2,x));
if(mid<r) ans=min(ans,query(l,r,mid+1,R,rt*2+1,x));
PushUp(rt);
return ans;
}
int main()
{
int n,q;
cin>>n>>q;
memset(minn,0,sizeof(minn));
for(int i=0; i<=q; i++)
{
Left[i]=n+1;
Right[i]=0;
}
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
Left[a[i]]=min(Left[a[i]],i);
Right[a[i]]=max(Right[a[i]],i);
}
if(Left[q]>Right[q])
{
if(Left[0]!=n+1)
{
Left[q]=Right[q]=Left[0];
a[Left[0]]=q;
}
else
{
printf("NO\n");
return 0;
}
}
int flag=0;
Build(1,n,1);
for(int i=q; i>=1; i--)
{
if(Left[i]>Right[i]) continue;
int temp=query(Left[i],Right[i],1,n,1,i);
if(temp<i)
{
flag=1;
break;
}
}
if(flag)
{
printf("NO\n");
return 0;
}
printf("YES\n");
for(int i=1; i<=n; i++)
{
if(i!=1) printf(" ");
if(a[i]!=0)
{
printf("%d",a[i]);
}
else printf("1");
}
printf("\n");
return 0;
}
/*
50 2
0 1 0 1 0 0 1 0 1 1 0 1 1 1 2 2 0 2 0 2 0 2 0 0 2 2 2 0 0 0 0 1 0 1 0 0 1 0 1 0 0 1 1 0 1 1 0 1 0 0
*/