Round #504 D. Array Restoration .

题目: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;
}

猜你喜欢

转载自www.cnblogs.com/lingyuanchuang/p/9498599.html