• Codeforces #504(div1+div2) 1023D Array Restoration(线段树)


    题目大意:给你一个数组,数组是经过q次区间覆盖后的结果,第i次覆盖是把区间内的值赋值为i,其中有若干个地方数值未知(就是0),让你判断这个数组是否可以经过覆盖后得到的,如果可以,输出任意一种可行数组。

    思路:不合法的情况只有2种。1:两个相同的数字中间出现了比它小的数字,比如: 6 5 6 就不合法,因为覆盖6的时候是覆盖连续的一段区间,而5比6先覆盖,所以这种情况不存在。我赛后看AC代码的时候发现有的人只是判断是否出现谷形的情况,这种是不对的。

    比如这种样例:3 3 3 1 2 这种判断方法会输出NO,但实际上却可以覆盖。那么怎么找任意区间内的最小值呢?线段树啊(比赛结束前10分钟才想到。。。)。

    2:最大值没出现过而且没有0,因为最大值是最后一次覆盖的,所以肯定有最大值。

    那么我们就可以写代码了:

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<string>
    #include<map>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<cmath>
    #include<queue>
    #include<stack>
    #define INF 0x3f3f3f3f
    #define LL long long
    #define mk(a,b) make_pair(a,b)
    #define pii pair<int,int> 
    using namespace std;
    const int maxn=200010;
    map<int,int> mp;
    int a[maxn],mi[maxn];
    bool vis[maxn];
    int minv[4*maxn];
    int ql,qr;
    int query(int o,int l,int r){//查询最小值 
    	int mid=l+(r-l)/2,ans=INF;
    	if(ql<=l&&r<=qr)return minv[o];
    	if(ql<=mid)ans=min(ans,query(o*2,l,mid));
    	if(mid<qr)ans=min(ans,query(o*2+1,mid+1,r));
    	return ans;
    }
    void build(int o,int l,int r){
    	if(l==r){
    		minv[o]=a[l];
    		return;
    	}
    	int mid=l+(r-l)/2;
    	build(o*2,l,mid);
    	build(o*2+1,mid+1,r);
    	minv[o]=min(minv[o*2],minv[o*2+1]); 
    }
    int main(){
    	int n,m,mi=INF,mx=0,cnt=0;
    	bool flag=1;
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    		mx=max(mx,a[i]);
    		if(a[i]==0){//为了方便建线段树,把0赋值为INF 
    			a[i]=INF;
    			cnt++;
    		}
    	}
    	if(mx<m&&cnt==0){//第二种情况 
    		printf("NO
    ");
    		return 0;
    	}
    	build(1,1,n);//建树 
    	for(int i=1;i<=n;i++){
    		if(a[i]==INF){
    			continue;
    		}
    		if(vis[a[i]]){//如果之前出现过 
    			ql=mp[a[i]],qr=i;
    			if(query(1,1,n)<a[i]){//如果小于a[i]值 
    				flag=0;
    				break;
    			}
    		}
    		vis[a[i]]=1;
    		mp[a[i]]=i;
    	}
    	if(flag==0){//情况1 
    		printf("NO
    ");
    		return 0;
    	}
    	for(int i=1,j;i<=n;i++){//从前往后扫一遍 
    		if(a[i]!=INF)continue;
    		else{
    			if(mx<m)a[i]=m;//如果最大值没出现,就赋值为最大值 
    			else a[i]=a[i-1];//否则赋值为他前面的值 
    			mx=max(mx,a[i]);
    		}
    	}
    	for(int i=n,j;i>=1;i--){
    		if(a[i]!=INF&&a[i]!=0)continue;//防止a[1]为0的情况 
    		else{
    			if(mx<m)a[i]=m;
    			else a[i]=a[i+1];
    			mx=max(mx,a[i]);
    		}
    	}
    	printf("YES
    ");
    	for(int i=1;i<=n;i++)
    		printf("%d ",a[i]);
    }
    

      

  • 相关阅读:
    Java并发指南3:并发三大问题与volatile关键字,CAS操作
    Java并发指南2:深入理解Java内存模型JMM
    Java并发指南1:并发基础与Java多线程
    Java集合详解8:Java集合类细节精讲,细节决定成败
    Java集合详解7:一文搞清楚HashSet,TreeSet与LinkedHashSet的异同
    Java集合详解6:这次,从头到尾带你解读Java中的红黑树
    IP电话的配置
    孤立账户
    服务器维护知识
    VB学习一
  • 原文地址:https://www.cnblogs.com/pkgunboat/p/9498169.html
Copyright © 2020-2023  润新知