题目:http://codeforces.com/contest/1023
对于一个长度n的数组进行q次查询,i从1到q,第i次将任意一段连续的部分全部染成i。
最后得到的数组中可能会存在“污点”0.即最后对数组的任意子集set为0.
给出n和q,以及带污点的长为n的数组,判断是否能将其还原成没有0的合理数组。
如果可以则输出任意一合理数组。
思路:先统计每个数的出现的最左位置和最右位置,然后从q到1查询,判断q的最左到最右中间有没有不合理的数(小于q)。
因为一定会有q次查询所有最后至少有一个q存在,否则就是被0覆盖了,所以要先判断q、0的存在问题。
如果无q有0,就将最左的0设置为q(其实任意了);
然后在判断是否合理,如果第i次判断时遇到了0可以直接将0设置为i,注意判断时一定要跳过已经判断了的部分。
注意初始化时的范围选择
#include<cstdio>
const int maxn = 200015;
int n,q,a[maxn],r[maxn],l[maxn],fa[maxn];
int mfind(int x){return fa[x]==x?x:fa[x]=mfind(fa[x]);}
int m_max(int i,int j){return i>j?i:j;}
int m_min(int i,int j){return i<j?i:j;}
int main(){
scanf("%d%d",&n,&q);
for(int i=0;i<=q;i++){//note is q
r[i]=0;
l[i]=n;
}
for(int i=0;i<n;i++){
scanf("%d",a+i);
r[a[i]]=m_max(r[a[i]],i);
l[a[i]]=m_min(l[a[i]],i);
}
for(int i=0;i<=n;i++)fa[i]=i;//note can equ n
if(l[q]>r[q]){
if(l[0]>r[0]){
puts("NO");
return 0;
}
a[l[0]]=q;
fa[l[0]]=mfind(l[0]+1);
}
for(int i=q;i;i--){
for(int j=mfind(l[i]);j<=r[i];j=mfind(j)){
if(a[j]<i&&a[j]){
puts("NO");
return 0;
}
a[j]=i;
fa[j]=mfind(j+1);
}
}
puts("YES");
for(int i=0;i<n;i++)
printf("%d ",a[i]?a[i]:1," \n"[i==n-1]);
return 0;
}
原文地址:https://www.cnblogs.com/lingyuanchuang/p/9498599.html
时间: 2024-11-08 15:55:17